style/properties_and_values/syntax/
mod.rs1use std::fmt::{self, Debug};
10use std::{borrow::Cow, fmt::Write};
11
12use crate::parser::{Parse, ParserContext};
13use crate::values::CustomIdent;
14use cssparser::{Parser as CSSParser, ParserInput as CSSParserInput};
15use style_traits::{
16 CssWriter, ParseError as StyleParseError, PropertySyntaxParseError as ParseError,
17 StyleParseErrorKind, ToCss,
18};
19
20use self::data_type::{DataType, DependentDataTypes};
21
22mod ascii;
23pub mod data_type;
24
25#[derive(Debug, Clone, Default, MallocSizeOf, PartialEq)]
27pub struct Descriptor {
28 pub components: Vec<Component>,
31 specified: Option<Box<str>>,
33}
34
35impl Descriptor {
36 pub const fn universal() -> Self {
38 Self {
39 components: Vec::new(),
40 specified: None,
41 }
42 }
43
44 #[inline]
46 pub fn is_universal(&self) -> bool {
47 self.components.is_empty()
48 }
49
50 #[inline]
52 pub fn specified_string(&self) -> Option<&str> {
53 self.specified.as_deref()
54 }
55
56 pub fn from_str(css: &str, save_specified: bool) -> Result<Self, ParseError> {
59 let input = ascii::trim_ascii_whitespace(css);
61
62 if input.is_empty() {
64 return Err(ParseError::EmptyInput);
65 }
66
67 let specified = if save_specified {
68 Some(Box::from(css))
69 } else {
70 None
71 };
72
73 if input.len() == 1 && input.as_bytes()[0] == b'*' {
76 return Ok(Self {
77 components: Default::default(),
78 specified,
79 });
80 }
81
82 let mut components = vec![];
89 {
90 let mut parser = Parser::new(input, &mut components);
91 parser.parse()?;
93 }
94 Ok(Self {
95 components,
96 specified,
97 })
98 }
99
100 pub fn dependent_types(&self) -> DependentDataTypes {
102 let mut types = DependentDataTypes::empty();
103 for component in self.components.iter() {
104 let t = match &component.name {
105 ComponentName::DataType(ref t) => t,
106 ComponentName::Ident(_) => continue,
107 };
108 types.insert(t.dependent_types());
109 }
110 types
111 }
112}
113
114impl ToCss for Descriptor {
115 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
116 where
117 W: Write,
118 {
119 if let Some(ref specified) = self.specified {
120 return specified.to_css(dest);
121 }
122
123 if self.is_universal() {
124 return dest.write_char('*');
125 }
126
127 let mut first = true;
128 for component in &*self.components {
129 if !first {
130 dest.write_str(" | ")?;
131 }
132 component.to_css(dest)?;
133 first = false;
134 }
135
136 Ok(())
137 }
138}
139
140impl Parse for Descriptor {
141 fn parse<'i>(
143 _: &ParserContext,
144 parser: &mut CSSParser<'i, '_>,
145 ) -> Result<Self, StyleParseError<'i>> {
146 let input = parser.expect_string()?;
147 Descriptor::from_str(input.as_ref(), true)
148 .map_err(|err| parser.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err)))
149 }
150}
151
152#[derive(
154 Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
155)]
156pub enum Multiplier {
157 Space,
159 Comma,
161}
162
163impl ToCss for Multiplier {
164 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
165 where
166 W: Write,
167 {
168 dest.write_char(match *self {
169 Multiplier::Space => '+',
170 Multiplier::Comma => '#',
171 })
172 }
173}
174
175#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
177pub struct Component {
178 name: ComponentName,
179 multiplier: Option<Multiplier>,
180}
181
182impl Component {
183 #[inline]
185 pub fn name(&self) -> &ComponentName {
186 &self.name
187 }
188
189 #[inline]
191 pub fn multiplier(&self) -> Option<Multiplier> {
192 self.multiplier
193 }
194
195 #[inline]
197 pub fn unpremultiplied(&self) -> Cow<Self> {
198 match self.name.unpremultiply() {
199 Some(component) => {
200 debug_assert!(
201 self.multiplier.is_none(),
202 "Shouldn't have parsed a multiplier for a pre-multiplied data type name",
203 );
204 Cow::Owned(component)
205 },
206 None => Cow::Borrowed(self),
207 }
208 }
209}
210
211impl ToCss for Component {
212 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
213 where
214 W: Write,
215 {
216 self.name().to_css(dest)?;
217 self.multiplier().to_css(dest)
218 }
219}
220
221#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
223pub enum ComponentName {
224 DataType(DataType),
226 Ident(CustomIdent),
228}
229
230impl ComponentName {
231 fn unpremultiply(&self) -> Option<Component> {
232 match *self {
233 ComponentName::DataType(ref t) => t.unpremultiply(),
234 ComponentName::Ident(..) => None,
235 }
236 }
237
238 fn is_pre_multiplied(&self) -> bool {
240 self.unpremultiply().is_some()
241 }
242}
243
244struct Parser<'a> {
245 input: &'a str,
246 position: usize,
247 output: &'a mut Vec<Component>,
248}
249
250fn is_letter(byte: u8) -> bool {
252 match byte {
253 b'A'..=b'Z' | b'a'..=b'z' => true,
254 _ => false,
255 }
256}
257
258fn is_non_ascii(byte: u8) -> bool {
260 byte >= 0x80
261}
262
263fn is_name_start(byte: u8) -> bool {
265 is_letter(byte) || is_non_ascii(byte) || byte == b'_'
266}
267
268impl<'a> Parser<'a> {
269 fn new(input: &'a str, output: &'a mut Vec<Component>) -> Self {
270 Self {
271 input,
272 position: 0,
273 output,
274 }
275 }
276
277 fn peek(&self) -> Option<u8> {
278 self.input.as_bytes().get(self.position).cloned()
279 }
280
281 fn parse(&mut self) -> Result<(), ParseError> {
282 loop {
284 let component = self.parse_component()?;
285 self.output.push(component);
286 self.skip_whitespace();
287
288 let byte = match self.peek() {
289 None => return Ok(()),
290 Some(b) => b,
291 };
292
293 if byte != b'|' {
294 return Err(ParseError::ExpectedPipeBetweenComponents);
295 }
296
297 self.position += 1;
298 }
299 }
300
301 fn skip_whitespace(&mut self) {
302 loop {
303 match self.peek() {
304 Some(c) if c.is_ascii_whitespace() => self.position += 1,
305 _ => return,
306 }
307 }
308 }
309
310 fn parse_data_type_name(&mut self) -> Result<DataType, ParseError> {
312 let start = self.position;
313 loop {
314 let byte = match self.peek() {
315 Some(b) => b,
316 None => return Err(ParseError::UnclosedDataTypeName),
317 };
318 if byte != b'>' {
319 self.position += 1;
320 continue;
321 }
322 let ty = match DataType::from_str(&self.input[start..self.position]) {
323 Some(ty) => ty,
324 None => return Err(ParseError::UnknownDataTypeName),
325 };
326 self.position += 1;
327 return Ok(ty);
328 }
329 }
330
331 fn parse_name(&mut self) -> Result<ComponentName, ParseError> {
332 let b = match self.peek() {
333 Some(b) => b,
334 None => return Err(ParseError::UnexpectedEOF),
335 };
336
337 if b == b'<' {
338 self.position += 1;
339 return Ok(ComponentName::DataType(self.parse_data_type_name()?));
340 }
341
342 if b != b'\\' && !is_name_start(b) {
343 return Err(ParseError::InvalidNameStart);
344 }
345
346 let input = &self.input[self.position..];
347 let mut input = CSSParserInput::new(input);
348 let mut input = CSSParser::new(&mut input);
349 let name = match CustomIdent::parse(&mut input, &[]) {
350 Ok(name) => name,
351 Err(_) => return Err(ParseError::InvalidName),
352 };
353 self.position += input.position().byte_index();
354 return Ok(ComponentName::Ident(name));
355 }
356
357 fn parse_multiplier(&mut self) -> Option<Multiplier> {
358 let multiplier = match self.peek()? {
359 b'+' => Multiplier::Space,
360 b'#' => Multiplier::Comma,
361 _ => return None,
362 };
363 self.position += 1;
364 Some(multiplier)
365 }
366
367 fn parse_component(&mut self) -> Result<Component, ParseError> {
369 self.skip_whitespace();
371 let name = self.parse_name()?;
372 let multiplier = if name.is_pre_multiplied() {
373 None
374 } else {
375 self.parse_multiplier()
376 };
377 Ok(Component { name, multiplier })
378 }
379}