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(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
154pub enum Multiplier {
155 Space,
157 Comma,
159}
160
161impl ToCss for Multiplier {
162 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
163 where
164 W: Write,
165 {
166 dest.write_char(match *self {
167 Multiplier::Space => '+',
168 Multiplier::Comma => '#',
169 })
170 }
171}
172
173#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
175pub struct Component {
176 name: ComponentName,
177 multiplier: Option<Multiplier>,
178}
179
180impl Component {
181 #[inline]
183 pub fn name(&self) -> &ComponentName {
184 &self.name
185 }
186
187 #[inline]
189 pub fn multiplier(&self) -> Option<Multiplier> {
190 self.multiplier
191 }
192
193 #[inline]
195 pub fn unpremultiplied(&self) -> Cow<Self> {
196 match self.name.unpremultiply() {
197 Some(component) => {
198 debug_assert!(
199 self.multiplier.is_none(),
200 "Shouldn't have parsed a multiplier for a pre-multiplied data type name",
201 );
202 Cow::Owned(component)
203 },
204 None => Cow::Borrowed(self),
205 }
206 }
207}
208
209impl ToCss for Component {
210 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
211 where
212 W: Write,
213 {
214 self.name().to_css(dest)?;
215 self.multiplier().to_css(dest)
216 }
217}
218
219#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
221pub enum ComponentName {
222 DataType(DataType),
224 Ident(CustomIdent),
226}
227
228impl ComponentName {
229 fn unpremultiply(&self) -> Option<Component> {
230 match *self {
231 ComponentName::DataType(ref t) => t.unpremultiply(),
232 ComponentName::Ident(..) => None,
233 }
234 }
235
236 fn is_pre_multiplied(&self) -> bool {
238 self.unpremultiply().is_some()
239 }
240}
241
242struct Parser<'a> {
243 input: &'a str,
244 position: usize,
245 output: &'a mut Vec<Component>,
246}
247
248fn is_letter(byte: u8) -> bool {
250 match byte {
251 b'A'..=b'Z' | b'a'..=b'z' => true,
252 _ => false,
253 }
254}
255
256fn is_non_ascii(byte: u8) -> bool {
258 byte >= 0x80
259}
260
261fn is_name_start(byte: u8) -> bool {
263 is_letter(byte) || is_non_ascii(byte) || byte == b'_'
264}
265
266impl<'a> Parser<'a> {
267 fn new(input: &'a str, output: &'a mut Vec<Component>) -> Self {
268 Self {
269 input,
270 position: 0,
271 output,
272 }
273 }
274
275 fn peek(&self) -> Option<u8> {
276 self.input.as_bytes().get(self.position).cloned()
277 }
278
279 fn parse(&mut self) -> Result<(), ParseError> {
280 loop {
282 let component = self.parse_component()?;
283 self.output.push(component);
284 self.skip_whitespace();
285
286 let byte = match self.peek() {
287 None => return Ok(()),
288 Some(b) => b,
289 };
290
291 if byte != b'|' {
292 return Err(ParseError::ExpectedPipeBetweenComponents);
293 }
294
295 self.position += 1;
296 }
297 }
298
299 fn skip_whitespace(&mut self) {
300 loop {
301 match self.peek() {
302 Some(c) if c.is_ascii_whitespace() => self.position += 1,
303 _ => return,
304 }
305 }
306 }
307
308 fn parse_data_type_name(&mut self) -> Result<DataType, ParseError> {
310 let start = self.position;
311 loop {
312 let byte = match self.peek() {
313 Some(b) => b,
314 None => return Err(ParseError::UnclosedDataTypeName),
315 };
316 if byte != b'>' {
317 self.position += 1;
318 continue;
319 }
320 let ty = match DataType::from_str(&self.input[start..self.position]) {
321 Some(ty) => ty,
322 None => return Err(ParseError::UnknownDataTypeName),
323 };
324 self.position += 1;
325 return Ok(ty);
326 }
327 }
328
329 fn parse_name(&mut self) -> Result<ComponentName, ParseError> {
330 let b = match self.peek() {
331 Some(b) => b,
332 None => return Err(ParseError::UnexpectedEOF),
333 };
334
335 if b == b'<' {
336 self.position += 1;
337 return Ok(ComponentName::DataType(self.parse_data_type_name()?));
338 }
339
340 if b != b'\\' && !is_name_start(b) {
341 return Err(ParseError::InvalidNameStart);
342 }
343
344 let input = &self.input[self.position..];
345 let mut input = CSSParserInput::new(input);
346 let mut input = CSSParser::new(&mut input);
347 let name = match CustomIdent::parse(&mut input, &[]) {
348 Ok(name) => name,
349 Err(_) => return Err(ParseError::InvalidName),
350 };
351 self.position += input.position().byte_index();
352 return Ok(ComponentName::Ident(name));
353 }
354
355 fn parse_multiplier(&mut self) -> Option<Multiplier> {
356 let multiplier = match self.peek()? {
357 b'+' => Multiplier::Space,
358 b'#' => Multiplier::Comma,
359 _ => return None,
360 };
361 self.position += 1;
362 Some(multiplier)
363 }
364
365 fn parse_component(&mut self) -> Result<Component, ParseError> {
367 self.skip_whitespace();
369 let name = self.parse_name()?;
370 let multiplier = if name.is_pre_multiplied() {
371 None
372 } else {
373 self.parse_multiplier()
374 };
375 Ok(Component { name, multiplier })
376 }
377}