swc_css_parser/parser/values_and_units/
mod.rs

1use swc_atoms::Atom;
2use swc_common::{BytePos, Span};
3use swc_css_ast::*;
4
5use super::{input::ParserInput, PResult, Parser};
6use crate::{
7    error::{Error, ErrorKind},
8    Parse,
9};
10
11impl<I> Parser<I>
12where
13    I: ParserInput,
14{
15    pub(super) fn parse_generic_values(&mut self) -> PResult<Vec<ComponentValue>> {
16        let mut values = Vec::new();
17
18        loop {
19            self.input.skip_ws();
20
21            if is!(self, EOF) {
22                break;
23            }
24
25            let component_value = self.parse_generic_value()?;
26
27            values.push(component_value);
28        }
29
30        Ok(values)
31    }
32
33    pub(super) fn parse_generic_value(&mut self) -> PResult<ComponentValue> {
34        self.input.skip_ws();
35
36        let span = self.input.cur_span();
37
38        match cur!(self) {
39            tok!(",") | tok!("/") | tok!(";") => {
40                return Ok(ComponentValue::Delimiter(self.parse()?));
41            }
42
43            tok!("string") => {
44                return Ok(ComponentValue::Str(self.parse()?));
45            }
46
47            tok!("url") => {
48                return Ok(ComponentValue::Url(self.parse()?));
49            }
50
51            Token::Function { value, .. } => match &*value.to_ascii_lowercase() {
52                "url" | "src" => {
53                    return Ok(ComponentValue::Url(self.parse()?));
54                }
55                "rgb" | "rgba" | "hsl" | "hsla" | "hwb" | "lab" | "lch" | "oklab" | "oklch"
56                | "color" | "device-cmyk" | "color-mix" | "color-contrast" => {
57                    return Ok(ComponentValue::Color(self.parse()?));
58                }
59                _ => {
60                    return Ok(ComponentValue::Function(self.parse()?));
61                }
62            },
63
64            tok!("percentage") => {
65                return Ok(ComponentValue::Percentage(self.parse()?));
66            }
67
68            tok!("dimension") => return Ok(ComponentValue::Dimension(self.parse()?)),
69
70            Token::Number { type_flag, .. } => {
71                if *type_flag == NumberType::Integer {
72                    return Ok(ComponentValue::Integer(self.parse()?));
73                }
74
75                return Ok(ComponentValue::Number(self.parse()?));
76            }
77
78            Token::Ident { value, .. } => {
79                if value.starts_with("--") {
80                    return Ok(ComponentValue::DashedIdent(self.parse()?));
81                } else if matches_eq_ignore_ascii_case!(value, "u")
82                    && peeked_is_one_of!(self, "+", "number", "dimension")
83                {
84                    return Ok(ComponentValue::UnicodeRange(self.parse()?));
85                }
86
87                return Ok(ComponentValue::Ident(self.parse()?));
88            }
89
90            tok!("[") | tok!("(") | tok!("{") => {
91                let mut block = self.parse_as::<SimpleBlock>()?;
92                let locv = self.create_locv(block.value);
93
94                block.value = match self
95                    .parse_according_to_grammar(&locv, |parser| parser.parse_generic_values())
96                {
97                    Ok(values) => values,
98                    Err(err) => {
99                        if *err.kind() != ErrorKind::Ignore {
100                            self.errors.push(err);
101                        }
102
103                        locv.children
104                    }
105                };
106
107                return Ok(ComponentValue::SimpleBlock(Box::new(block)));
108            }
109
110            tok!("#") => {
111                return Ok(ComponentValue::Color(self.parse()?));
112            }
113
114            _ => {}
115        }
116
117        Err(Error::new(span, ErrorKind::Expected("Declaration value")))
118    }
119
120    /// Parse value as <any-value>.
121    pub(super) fn parse_any_value(&mut self) -> PResult<Vec<TokenAndSpan>> {
122        let mut tokens = Vec::new();
123        let mut balance_stack: Vec<Option<char>> = Vec::new();
124
125        // The <any-value> production matches any sequence of one or more tokens,
126        // so long as the sequence ...
127        loop {
128            if is!(self, EOF) {
129                break;
130            }
131
132            match cur!(self) {
133                // ... <bad-string-token>, <bad-url-token>,
134                tok!("bad-string") | tok!("bad-url") => {
135                    break;
136                }
137
138                // ... unmatched <)-token>, <]-token>, or <}-token>,
139                tok!(")") | tok!("]") | tok!("}") => {
140                    let value = match cur!(self) {
141                        tok!(")") => ')',
142                        tok!("]") => ']',
143                        tok!("}") => '}',
144                        _ => {
145                            unreachable!();
146                        }
147                    };
148
149                    let balance_close_type = balance_stack.pop().unwrap_or_default();
150
151                    if Some(value) != balance_close_type {
152                        break;
153                    }
154                }
155
156                tok!("function") | tok!("(") | tok!("[") | tok!("{") => {
157                    let value = match cur!(self) {
158                        tok!("function") | tok!("(") => ')',
159                        tok!("[") => ']',
160                        tok!("{") => '}',
161                        _ => {
162                            unreachable!();
163                        }
164                    };
165
166                    balance_stack.push(Some(value));
167                }
168
169                _ => {}
170            }
171
172            let token = self.input.bump();
173
174            match token {
175                Some(token) => tokens.push(token),
176                None => break,
177            }
178        }
179
180        Ok(tokens)
181    }
182
183    // TODO use `Atom`
184    pub fn parse_function_values(
185        &mut self,
186        function_name: &FunctionName,
187    ) -> PResult<Vec<ComponentValue>> {
188        let function_name = match function_name {
189            FunctionName::Ident(name) => &name.value,
190            FunctionName::DashedIdent(_) => {
191                return Err(Error::new(Default::default(), ErrorKind::Ignore))
192            }
193        };
194
195        let mut values = Vec::new();
196
197        let lower_fname = function_name.to_ascii_lowercase();
198
199        match &*lower_fname {
200            "calc" | "-moz-calc" | "-webkit-calc" | "sin" | "cos" | "tan" | "asin" | "acos"
201            | "atan" | "sqrt" | "exp" | "abs" | "sign" => {
202                self.input.skip_ws();
203
204                let calc_sum = ComponentValue::CalcSum(self.parse()?);
205
206                values.push(calc_sum);
207
208                self.input.skip_ws();
209
210                if !is!(self, EOF) {
211                    let span = self.input.cur_span();
212
213                    return Err(Error::new(span, ErrorKind::Unexpected("value")));
214                }
215            }
216            "min" | "max" | "hypot" => {
217                self.input.skip_ws();
218
219                let calc_sum = ComponentValue::CalcSum(self.parse()?);
220
221                values.push(calc_sum);
222
223                loop {
224                    self.input.skip_ws();
225
226                    if is!(self, ",") {
227                        values.push(ComponentValue::Delimiter(self.parse()?));
228
229                        self.input.skip_ws();
230                    } else {
231                        break;
232                    }
233
234                    let calc_sum = ComponentValue::CalcSum(self.parse()?);
235
236                    values.push(calc_sum);
237                }
238
239                if !is!(self, EOF) {
240                    let span = self.input.cur_span();
241
242                    return Err(Error::new(span, ErrorKind::Unexpected("value")));
243                }
244            }
245            "clamp" => {
246                self.input.skip_ws();
247
248                let calc_sum = ComponentValue::CalcSum(self.parse()?);
249
250                values.push(calc_sum);
251
252                self.input.skip_ws();
253
254                if is!(self, ",") {
255                    values.push(ComponentValue::Delimiter(self.parse()?));
256
257                    self.input.skip_ws();
258                } else {
259                    let span = self.input.cur_span();
260
261                    return Err(Error::new(span, ErrorKind::Expected("',' delim token")));
262                }
263
264                let calc_sum = ComponentValue::CalcSum(self.parse()?);
265
266                values.push(calc_sum);
267
268                self.input.skip_ws();
269
270                if is!(self, ",") {
271                    values.push(ComponentValue::Delimiter(self.parse()?));
272
273                    self.input.skip_ws();
274                } else {
275                    let span = self.input.cur_span();
276
277                    return Err(Error::new(span, ErrorKind::Expected("',' delim token")));
278                }
279
280                let calc_sum = ComponentValue::CalcSum(self.parse()?);
281
282                values.push(calc_sum);
283
284                self.input.skip_ws();
285            }
286            "round" => {
287                self.input.skip_ws();
288
289                if is!(self, "ident") {
290                    // TODO improve me
291                    let rounding_strategy = ComponentValue::Ident(self.parse()?);
292
293                    values.push(rounding_strategy);
294
295                    self.input.skip_ws();
296
297                    if is!(self, ",") {
298                        values.push(ComponentValue::Delimiter(self.parse()?));
299
300                        self.input.skip_ws();
301                    } else {
302                        let span = self.input.cur_span();
303
304                        return Err(Error::new(span, ErrorKind::Expected("',' delim token")));
305                    }
306                }
307
308                let calc_sum = ComponentValue::CalcSum(self.parse()?);
309
310                values.push(calc_sum);
311
312                self.input.skip_ws();
313
314                if is!(self, ",") {
315                    values.push(ComponentValue::Delimiter(self.parse()?));
316
317                    self.input.skip_ws();
318                } else {
319                    let span = self.input.cur_span();
320
321                    return Err(Error::new(span, ErrorKind::Expected("',' delim token")));
322                }
323
324                let calc_sum = ComponentValue::CalcSum(self.parse()?);
325
326                values.push(calc_sum);
327
328                self.input.skip_ws();
329            }
330            "mod" | "rem" | "atan2" | "pow" => {
331                self.input.skip_ws();
332
333                let calc_sum = ComponentValue::CalcSum(self.parse()?);
334
335                values.push(calc_sum);
336
337                self.input.skip_ws();
338
339                if is!(self, ",") {
340                    values.push(ComponentValue::Delimiter(self.parse()?));
341
342                    self.input.skip_ws();
343                } else {
344                    let span = self.input.cur_span();
345
346                    return Err(Error::new(span, ErrorKind::Expected("',' delim token")));
347                }
348
349                let calc_sum = ComponentValue::CalcSum(self.parse()?);
350
351                values.push(calc_sum);
352
353                self.input.skip_ws();
354            }
355            "log" => {
356                self.input.skip_ws();
357
358                let calc_sum = ComponentValue::CalcSum(self.parse()?);
359
360                values.push(calc_sum);
361
362                self.input.skip_ws();
363
364                if is!(self, ",") {
365                    values.push(ComponentValue::Delimiter(self.parse()?));
366
367                    self.input.skip_ws();
368
369                    let calc_sum = ComponentValue::CalcSum(self.parse()?);
370
371                    values.push(calc_sum);
372
373                    self.input.skip_ws();
374                }
375            }
376            "rgb" | "rgba" | "hsl" | "hsla" => {
377                self.input.skip_ws();
378
379                let mut has_variable = false;
380                let mut is_legacy_syntax = true;
381
382                match cur!(self) {
383                    Token::Ident { value, .. } if matches_eq_ignore_ascii_case!(value, "from") => {
384                        is_legacy_syntax = false;
385
386                        values.push(ComponentValue::Ident(self.parse()?));
387
388                        self.input.skip_ws();
389
390                        let color = self.try_parse_variable_function(
391                            |parser, _| Ok(Some(ComponentValue::Color(parser.parse()?))),
392                            &mut has_variable,
393                        )?;
394
395                        if let Some(color) = color {
396                            values.push(color);
397                        }
398
399                        self.input.skip_ws();
400                    }
401                    _ => {}
402                }
403
404                match &*lower_fname {
405                    "rgb" | "rgba" => {
406                        let percentage_or_number_or_none = self.try_parse_variable_function(
407                            |parser, has_variable_before| match cur!(parser) {
408                                tok!("percentage") => {
409                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
410                                }
411                                tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
412                                Token::Function { value, .. } if is_math_function(value) => {
413                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
414                                }
415                                tok!("ident") => {
416                                    is_legacy_syntax = false;
417
418                                    let ident: Box<Ident> = parser.parse()?;
419
420                                    if ident.value.eq_ignore_ascii_case("none") {
421                                        Ok(Some(ComponentValue::Ident(ident)))
422                                    } else {
423                                        Err(Error::new(
424                                            ident.span,
425                                            ErrorKind::Expected("'none' value of an ident token"),
426                                        ))
427                                    }
428                                }
429                                _ => {
430                                    if !has_variable_before {
431                                        Err(Error::new(
432                                            parser.input.cur_span(),
433                                            ErrorKind::Expected(
434                                                "percentage, number, function (math functions) or \
435                                                 ident (with 'none' value) token",
436                                            ),
437                                        ))
438                                    } else {
439                                        Ok(None)
440                                    }
441                                }
442                            },
443                            &mut has_variable,
444                        )?;
445
446                        if let Some(percentage_or_number_or_none) = percentage_or_number_or_none {
447                            values.push(percentage_or_number_or_none);
448                        }
449
450                        self.input.skip_ws();
451                    }
452                    "hsl" | "hsla" => {
453                        let hue_or_none = self.try_parse_variable_function(
454                            |parser, has_variable_before| match cur!(parser) {
455                                tok!("number") | tok!("dimension") => {
456                                    Ok(Some(ComponentValue::Hue(parser.parse()?)))
457                                }
458                                tok!("ident") => {
459                                    let ident: Box<Ident> = parser.parse()?;
460
461                                    if ident.value.eq_ignore_ascii_case("none") {
462                                        Ok(Some(ComponentValue::Ident(ident)))
463                                    } else {
464                                        Err(Error::new(
465                                            ident.span,
466                                            ErrorKind::Expected("'none' value of an ident token"),
467                                        ))
468                                    }
469                                }
470                                Token::Function { value, .. } if is_math_function(value) => {
471                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
472                                }
473                                _ => {
474                                    if !has_variable_before {
475                                        Err(Error::new(
476                                            parser.input.cur_span(),
477                                            ErrorKind::Expected(
478                                                "number, dimension, function (math functions) or \
479                                                 ident (with 'none' value) token",
480                                            ),
481                                        ))
482                                    } else {
483                                        Ok(None)
484                                    }
485                                }
486                            },
487                            &mut has_variable,
488                        )?;
489
490                        if let Some(hue_or_none) = hue_or_none {
491                            values.push(hue_or_none);
492                        }
493
494                        self.input.skip_ws();
495                    }
496                    _ => {
497                        unreachable!()
498                    }
499                }
500
501                if is!(self, ",") {
502                    if !is_legacy_syntax && !has_variable {
503                        let span = self.input.cur_span();
504
505                        return Err(Error::new(span, ErrorKind::Expected("comma token")));
506                    }
507
508                    is_legacy_syntax = true;
509
510                    values.push(ComponentValue::Delimiter(self.parse()?));
511
512                    self.input.skip_ws();
513                } else {
514                    is_legacy_syntax = false;
515                }
516
517                match &*lower_fname {
518                    "rgb" | "rgba" => {
519                        let percentage_or_number = self.try_parse_variable_function(
520                            |parser, has_variable_before| match cur!(parser) {
521                                tok!("percentage") => {
522                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
523                                }
524                                tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
525                                Token::Function { value, .. } if is_math_function(value) => {
526                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
527                                }
528                                tok!("ident") if !is_legacy_syntax => {
529                                    let ident: Box<Ident> = parser.parse()?;
530
531                                    if ident.value.eq_ignore_ascii_case("none") {
532                                        Ok(Some(ComponentValue::Ident(ident)))
533                                    } else {
534                                        Err(Error::new(
535                                            ident.span,
536                                            ErrorKind::Expected("'none' value of an ident token"),
537                                        ))
538                                    }
539                                }
540                                _ => {
541                                    if !has_variable_before {
542                                        Err(Error::new(
543                                            parser.input.cur_span(),
544                                            ErrorKind::Expected(
545                                                "percentage, number, function (math functions) or \
546                                                 ident (with 'none' value) token",
547                                            ),
548                                        ))
549                                    } else {
550                                        Ok(None)
551                                    }
552                                }
553                            },
554                            &mut has_variable,
555                        )?;
556
557                        if let Some(percentage_or_number) = percentage_or_number {
558                            values.push(percentage_or_number);
559                        }
560
561                        self.input.skip_ws();
562                    }
563                    "hsl" | "hsla" => {
564                        let percentage_or_none = self.try_parse_variable_function(
565                            |parser, has_variable_before| match cur!(parser) {
566                                tok!("percentage") => {
567                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
568                                }
569                                Token::Function { value, .. } if is_math_function(value) => {
570                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
571                                }
572                                tok!("ident") => {
573                                    let ident: Box<Ident> = parser.parse()?;
574
575                                    if ident.value.eq_ignore_ascii_case("none") {
576                                        Ok(Some(ComponentValue::Ident(ident)))
577                                    } else {
578                                        Err(Error::new(
579                                            ident.span,
580                                            ErrorKind::Expected("'none' value of an ident token"),
581                                        ))
582                                    }
583                                }
584                                _ => {
585                                    if !has_variable_before {
586                                        Err(Error::new(
587                                            parser.input.cur_span(),
588                                            ErrorKind::Expected(
589                                                "percentage, function (math functions) or ident \
590                                                 (with 'none' value) token",
591                                            ),
592                                        ))
593                                    } else {
594                                        Ok(None)
595                                    }
596                                }
597                            },
598                            &mut has_variable,
599                        )?;
600
601                        if let Some(percentage_or_none) = percentage_or_none {
602                            values.push(percentage_or_none);
603                        }
604
605                        self.input.skip_ws();
606                    }
607                    _ => {
608                        unreachable!();
609                    }
610                }
611
612                if is_legacy_syntax {
613                    if has_variable && is!(self, EOF) {
614                        return Ok(values);
615                    }
616
617                    match cur!(self) {
618                        tok!(",") => {
619                            values.push(ComponentValue::Delimiter(self.parse()?));
620
621                            self.input.skip_ws();
622                        }
623                        _ => {
624                            if !has_variable {
625                                let span = self.input.cur_span();
626
627                                return Err(Error::new(span, ErrorKind::Expected("comma token")));
628                            }
629                        }
630                    }
631                }
632
633                match &*lower_fname {
634                    "rgb" | "rgba" => {
635                        let percentage_or_number = self.try_parse_variable_function(
636                            |parser, has_variable_before| match cur!(parser) {
637                                tok!("percentage") => {
638                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
639                                }
640                                tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
641                                Token::Function { value, .. } if is_math_function(value) => {
642                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
643                                }
644                                tok!("ident") if !is_legacy_syntax => {
645                                    let ident: Box<Ident> = parser.parse()?;
646
647                                    if ident.value.eq_ignore_ascii_case("none") {
648                                        Ok(Some(ComponentValue::Ident(ident)))
649                                    } else {
650                                        Err(Error::new(
651                                            ident.span,
652                                            ErrorKind::Expected("'none' value of an ident token"),
653                                        ))
654                                    }
655                                }
656                                _ => {
657                                    if !has_variable_before {
658                                        Err(Error::new(
659                                            parser.input.cur_span(),
660                                            ErrorKind::Expected(
661                                                "percentage, number, function (math functions) or \
662                                                 ident (with 'none' value) token",
663                                            ),
664                                        ))
665                                    } else {
666                                        Ok(None)
667                                    }
668                                }
669                            },
670                            &mut has_variable,
671                        )?;
672
673                        if let Some(percentage_or_number) = percentage_or_number {
674                            values.push(percentage_or_number);
675                        }
676
677                        self.input.skip_ws();
678                    }
679                    "hsl" | "hsla" => {
680                        let percentage_or_none = self.try_parse_variable_function(
681                            |parser, has_variable_before| match cur!(parser) {
682                                tok!("percentage") => {
683                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
684                                }
685                                Token::Function { value, .. } if is_math_function(value) => {
686                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
687                                }
688                                tok!("ident") => {
689                                    let ident: Box<Ident> = parser.parse()?;
690
691                                    if ident.value.eq_ignore_ascii_case("none") {
692                                        Ok(Some(ComponentValue::Ident(ident)))
693                                    } else {
694                                        Err(Error::new(
695                                            ident.span,
696                                            ErrorKind::Expected("'none' value of an ident token"),
697                                        ))
698                                    }
699                                }
700                                _ => {
701                                    if !has_variable_before {
702                                        Err(Error::new(
703                                            parser.input.cur_span(),
704                                            ErrorKind::Expected(
705                                                "percentage, function (math functions) or ident \
706                                                 (with 'none' value) token",
707                                            ),
708                                        ))
709                                    } else {
710                                        Ok(None)
711                                    }
712                                }
713                            },
714                            &mut has_variable,
715                        )?;
716
717                        if let Some(percentage_or_none) = percentage_or_none {
718                            values.push(percentage_or_none);
719                        }
720
721                        self.input.skip_ws();
722                    }
723                    _ => {
724                        unreachable!();
725                    }
726                }
727
728                if (is!(self, ",") || has_variable) && is_legacy_syntax {
729                    if is!(self, ",") {
730                        values.push(ComponentValue::Delimiter(self.parse()?));
731                    }
732
733                    self.input.skip_ws();
734
735                    let alpha_value = self.try_parse_variable_function(
736                        |parser, has_variable_before| match cur!(parser) {
737                            tok!("number") | tok!("percentage") => {
738                                Ok(Some(ComponentValue::AlphaValue(parser.parse()?)))
739                            }
740                            Token::Function { value, .. } if is_math_function(value) => {
741                                Ok(Some(ComponentValue::Function(parser.parse()?)))
742                            }
743                            _ => {
744                                if !has_variable_before {
745                                    Err(Error::new(
746                                        parser.input.cur_span(),
747                                        ErrorKind::Expected(
748                                            "percentage, function (math functions) or number token",
749                                        ),
750                                    ))
751                                } else {
752                                    Ok(None)
753                                }
754                            }
755                        },
756                        &mut has_variable,
757                    )?;
758
759                    if let Some(alpha_value) = alpha_value {
760                        values.push(alpha_value);
761                    }
762
763                    self.input.skip_ws();
764                } else if is!(self, "/") && !is_legacy_syntax {
765                    values.push(ComponentValue::Delimiter(self.parse()?));
766
767                    self.input.skip_ws();
768
769                    let alpha_value = self.try_parse_variable_function(
770                        |parser, has_variable_before| match cur!(parser) {
771                            tok!("number") | tok!("percentage") => {
772                                Ok(Some(ComponentValue::AlphaValue(parser.parse()?)))
773                            }
774                            Token::Function { value, .. } if is_math_function(value) => {
775                                Ok(Some(ComponentValue::Function(parser.parse()?)))
776                            }
777                            tok!("ident") => {
778                                let ident: Box<Ident> = parser.parse()?;
779
780                                if ident.value.eq_ignore_ascii_case("none") {
781                                    Ok(Some(ComponentValue::Ident(ident)))
782                                } else {
783                                    Err(Error::new(
784                                        ident.span,
785                                        ErrorKind::Expected("'none' value of an ident token"),
786                                    ))
787                                }
788                            }
789                            _ => {
790                                if !has_variable_before {
791                                    Err(Error::new(
792                                        parser.input.cur_span(),
793                                        ErrorKind::Expected(
794                                            "percentage, number, function (math functions) or \
795                                             ident (with 'none' value) token",
796                                        ),
797                                    ))
798                                } else {
799                                    Ok(None)
800                                }
801                            }
802                        },
803                        &mut has_variable,
804                    )?;
805
806                    if let Some(alpha_value) = alpha_value {
807                        values.push(alpha_value);
808                    }
809
810                    self.input.skip_ws();
811                }
812            }
813            "hwb" | "lab" | "lch" | "oklab" | "oklch" | "device-cmyk" => {
814                self.input.skip_ws();
815
816                let mut has_variable = false;
817
818                match cur!(self) {
819                    Token::Ident { value, .. }
820                        if matches_eq_ignore_ascii_case!(value, "from")
821                            && lower_fname != "device-cmyk" =>
822                    {
823                        values.push(ComponentValue::Ident(self.parse()?));
824
825                        self.input.skip_ws();
826
827                        let color = self.try_parse_variable_function(
828                            |parser, _| Ok(Some(ComponentValue::Color(parser.parse()?))),
829                            &mut has_variable,
830                        )?;
831
832                        if let Some(color) = color {
833                            values.push(color);
834                        }
835
836                        self.input.skip_ws();
837                    }
838                    _ => {}
839                }
840
841                match &*lower_fname {
842                    "hwb" => {
843                        let hue_or_none = self.try_parse_variable_function(
844                            |parser, has_variable_before| match cur!(parser) {
845                                tok!("number") | tok!("dimension") => {
846                                    Ok(Some(ComponentValue::Hue(parser.parse()?)))
847                                }
848                                Token::Function { value, .. } if is_math_function(value) => {
849                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
850                                }
851                                tok!("ident") => {
852                                    let ident: Box<Ident> = parser.parse()?;
853
854                                    if ident.value.eq_ignore_ascii_case("none") {
855                                        Ok(Some(ComponentValue::Ident(ident)))
856                                    } else {
857                                        Err(Error::new(
858                                            ident.span,
859                                            ErrorKind::Expected("'none' value of an ident token"),
860                                        ))
861                                    }
862                                }
863                                _ => {
864                                    if !has_variable_before {
865                                        return Err(Error::new(
866                                            parser.input.cur_span(),
867                                            ErrorKind::Expected(
868                                                "number, dimension, function (math functions) or \
869                                                 ident (with 'none' value) token",
870                                            ),
871                                        ));
872                                    } else {
873                                        Ok(None)
874                                    }
875                                }
876                            },
877                            &mut has_variable,
878                        )?;
879
880                        if let Some(hue_or_none) = hue_or_none {
881                            values.push(hue_or_none);
882                        }
883
884                        self.input.skip_ws();
885                    }
886                    "lab" | "lch" | "oklab" | "oklch" => {
887                        let percentage_or_none = self.try_parse_variable_function(
888                            |parser, has_variable_before| match cur!(parser) {
889                                tok!("percentage") => {
890                                    Ok(Some(ComponentValue::Percentage(parser.parse()?)))
891                                }
892                                tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
893                                Token::Function { value, .. } if is_math_function(value) => {
894                                    Ok(Some(ComponentValue::Function(parser.parse()?)))
895                                }
896                                tok!("ident") => {
897                                    let ident: Box<Ident> = parser.parse()?;
898
899                                    if ident.value.eq_ignore_ascii_case("none") {
900                                        Ok(Some(ComponentValue::Ident(ident)))
901                                    } else {
902                                        Err(Error::new(
903                                            ident.span,
904                                            ErrorKind::Expected("'none' value of an ident token"),
905                                        ))
906                                    }
907                                }
908                                _ => {
909                                    if !has_variable_before {
910                                        Err(Error::new(
911                                            parser.input.cur_span(),
912                                            ErrorKind::Expected(
913                                                "percentage, function (math functions) or ident \
914                                                 (with 'none' value) token",
915                                            ),
916                                        ))
917                                    } else {
918                                        Ok(None)
919                                    }
920                                }
921                            },
922                            &mut has_variable,
923                        )?;
924
925                        if let Some(percentage_or_none) = percentage_or_none {
926                            values.push(percentage_or_none);
927                        }
928
929                        self.input.skip_ws();
930                    }
931                    "device-cmyk" => {
932                        let cmyk_component = self.try_parse_variable_function(
933                            |parser, _| Ok(Some(ComponentValue::CmykComponent(parser.parse()?))),
934                            &mut has_variable,
935                        )?;
936
937                        if let Some(cmyk_component) = cmyk_component {
938                            values.push(cmyk_component);
939                        }
940
941                        self.input.skip_ws();
942                    }
943                    _ => {
944                        unreachable!();
945                    }
946                }
947
948                if !is_one_of!(self, EOF, "/") {
949                    match &*lower_fname {
950                        "hwb" => {
951                            let percentage_or_none = self.try_parse_variable_function(
952                                |parser, has_variable_before| match cur!(parser) {
953                                    tok!("percentage") => {
954                                        Ok(Some(ComponentValue::Percentage(parser.parse()?)))
955                                    }
956                                    Token::Function { value, .. } if is_math_function(value) => {
957                                        Ok(Some(ComponentValue::Function(parser.parse()?)))
958                                    }
959                                    tok!("ident") => {
960                                        let ident: Box<Ident> = parser.parse()?;
961
962                                        if ident.value.eq_ignore_ascii_case("none") {
963                                            Ok(Some(ComponentValue::Ident(ident)))
964                                        } else {
965                                            Err(Error::new(
966                                                ident.span,
967                                                ErrorKind::Expected(
968                                                    "'none' value of an ident token",
969                                                ),
970                                            ))
971                                        }
972                                    }
973                                    _ => {
974                                        if !has_variable_before {
975                                            Err(Error::new(
976                                                parser.input.cur_span(),
977                                                ErrorKind::Expected(
978                                                    "percentage, functions (math functions) or \
979                                                     ident (with 'none' value) token",
980                                                ),
981                                            ))
982                                        } else {
983                                            Ok(None)
984                                        }
985                                    }
986                                },
987                                &mut has_variable,
988                            )?;
989
990                            if let Some(percentage_or_none) = percentage_or_none {
991                                values.push(percentage_or_none);
992                            }
993
994                            self.input.skip_ws();
995                        }
996                        "lab" | "lch" | "oklab" | "oklch" => {
997                            let number_or_none = self.try_parse_variable_function(
998                                |parser, has_variable_before| match cur!(parser) {
999                                    tok!("percentage") => {
1000                                        Ok(Some(ComponentValue::Percentage(parser.parse()?)))
1001                                    }
1002                                    tok!("number") => {
1003                                        Ok(Some(ComponentValue::Number(parser.parse()?)))
1004                                    }
1005                                    Token::Function { value, .. } if is_math_function(value) => {
1006                                        Ok(Some(ComponentValue::Function(parser.parse()?)))
1007                                    }
1008                                    tok!("ident") => {
1009                                        let ident: Box<Ident> = parser.parse()?;
1010
1011                                        if ident.value.eq_ignore_ascii_case("none") {
1012                                            Ok(Some(ComponentValue::Ident(ident)))
1013                                        } else {
1014                                            Err(Error::new(
1015                                                ident.span,
1016                                                ErrorKind::Expected(
1017                                                    "'none' value of an ident token",
1018                                                ),
1019                                            ))
1020                                        }
1021                                    }
1022                                    _ => {
1023                                        if !has_variable_before {
1024                                            Err(Error::new(
1025                                                parser.input.cur_span(),
1026                                                ErrorKind::Expected(
1027                                                    "number, functions (math functions) or ident \
1028                                                     (with 'none' value) token",
1029                                                ),
1030                                            ))
1031                                        } else {
1032                                            Ok(None)
1033                                        }
1034                                    }
1035                                },
1036                                &mut has_variable,
1037                            )?;
1038
1039                            if let Some(number_or_none) = number_or_none {
1040                                values.push(number_or_none);
1041                            }
1042
1043                            self.input.skip_ws();
1044                        }
1045                        "device-cmyk" => {
1046                            let cmyk_component = self.try_parse_variable_function(
1047                                |parser, _| {
1048                                    Ok(Some(ComponentValue::CmykComponent(parser.parse()?)))
1049                                },
1050                                &mut has_variable,
1051                            )?;
1052
1053                            if let Some(cmyk_component) = cmyk_component {
1054                                values.push(cmyk_component);
1055                            }
1056
1057                            self.input.skip_ws();
1058                        }
1059                        _ => {
1060                            unreachable!();
1061                        }
1062                    }
1063                }
1064
1065                if !is_one_of!(self, EOF, "/") {
1066                    match &*lower_fname {
1067                        "hwb" => {
1068                            let percentage_or_none = self.try_parse_variable_function(
1069                                |parser, has_variable_before| match cur!(parser) {
1070                                    tok!("percentage") => {
1071                                        Ok(Some(ComponentValue::Percentage(parser.parse()?)))
1072                                    }
1073                                    Token::Function { value, .. } if is_math_function(value) => {
1074                                        Ok(Some(ComponentValue::Function(parser.parse()?)))
1075                                    }
1076                                    tok!("ident") => {
1077                                        let ident: Box<Ident> = parser.parse()?;
1078
1079                                        if ident.value.eq_ignore_ascii_case("none") {
1080                                            Ok(Some(ComponentValue::Ident(ident)))
1081                                        } else {
1082                                            Err(Error::new(
1083                                                ident.span,
1084                                                ErrorKind::Expected(
1085                                                    "'none' value of an ident token",
1086                                                ),
1087                                            ))
1088                                        }
1089                                    }
1090                                    _ => {
1091                                        if !has_variable_before {
1092                                            Err(Error::new(
1093                                                parser.input.cur_span(),
1094                                                ErrorKind::Expected(
1095                                                    "percentage, functions (math functions) or \
1096                                                     ident (with 'none' value) token",
1097                                                ),
1098                                            ))
1099                                        } else {
1100                                            Ok(None)
1101                                        }
1102                                    }
1103                                },
1104                                &mut has_variable,
1105                            )?;
1106
1107                            if let Some(percentage_or_none) = percentage_or_none {
1108                                values.push(percentage_or_none);
1109                            }
1110
1111                            self.input.skip_ws();
1112                        }
1113                        "lab" | "oklab" => {
1114                            let number_or_none = self.try_parse_variable_function(
1115                                |parser, has_variable_before| match cur!(parser) {
1116                                    tok!("percentage") => {
1117                                        Ok(Some(ComponentValue::Percentage(parser.parse()?)))
1118                                    }
1119                                    tok!("number") => {
1120                                        Ok(Some(ComponentValue::Number(parser.parse()?)))
1121                                    }
1122                                    Token::Function { value, .. } if is_math_function(value) => {
1123                                        Ok(Some(ComponentValue::Function(parser.parse()?)))
1124                                    }
1125                                    tok!("ident") => {
1126                                        let ident: Box<Ident> = parser.parse()?;
1127
1128                                        if ident.value.eq_ignore_ascii_case("none") {
1129                                            Ok(Some(ComponentValue::Ident(ident)))
1130                                        } else {
1131                                            Err(Error::new(
1132                                                ident.span,
1133                                                ErrorKind::Expected(
1134                                                    "'none' value of an ident token",
1135                                                ),
1136                                            ))
1137                                        }
1138                                    }
1139                                    _ => {
1140                                        if !has_variable_before {
1141                                            Err(Error::new(
1142                                                parser.input.cur_span(),
1143                                                ErrorKind::Expected(
1144                                                    "number, function (math functions) or ident \
1145                                                     (with 'none' value) token",
1146                                                ),
1147                                            ))
1148                                        } else {
1149                                            Ok(None)
1150                                        }
1151                                    }
1152                                },
1153                                &mut has_variable,
1154                            )?;
1155
1156                            if let Some(number_or_none) = number_or_none {
1157                                values.push(number_or_none);
1158                            }
1159
1160                            self.input.skip_ws();
1161                        }
1162                        "lch" | "oklch" => {
1163                            let hue_or_none = self.try_parse_variable_function(
1164                                |parser, has_variable_before| match cur!(parser) {
1165                                    tok!("number") | tok!("dimension") => {
1166                                        Ok(Some(ComponentValue::Hue(parser.parse()?)))
1167                                    }
1168                                    Token::Function { value, .. } if is_math_function(value) => {
1169                                        Ok(Some(ComponentValue::Function(parser.parse()?)))
1170                                    }
1171                                    tok!("ident") => {
1172                                        let ident: Box<Ident> = parser.parse()?;
1173
1174                                        if ident.value.eq_ignore_ascii_case("none") {
1175                                            Ok(Some(ComponentValue::Ident(ident)))
1176                                        } else {
1177                                            Err(Error::new(
1178                                                ident.span,
1179                                                ErrorKind::Expected(
1180                                                    "'none' value of an ident token",
1181                                                ),
1182                                            ))
1183                                        }
1184                                    }
1185                                    _ => {
1186                                        if !has_variable_before {
1187                                            return Err(Error::new(
1188                                                parser.input.cur_span(),
1189                                                ErrorKind::Expected(
1190                                                    "number, dimension, functions (math \
1191                                                     functions) or ident (with 'none' value) token",
1192                                                ),
1193                                            ));
1194                                        } else {
1195                                            Ok(None)
1196                                        }
1197                                    }
1198                                },
1199                                &mut has_variable,
1200                            )?;
1201
1202                            if let Some(hue_or_none) = hue_or_none {
1203                                values.push(hue_or_none);
1204                            }
1205
1206                            self.input.skip_ws();
1207                        }
1208                        "device-cmyk" => {
1209                            let cmyk_component = self.try_parse_variable_function(
1210                                |parser, _| {
1211                                    Ok(Some(ComponentValue::CmykComponent(parser.parse()?)))
1212                                },
1213                                &mut has_variable,
1214                            )?;
1215
1216                            if let Some(cmyk_component) = cmyk_component {
1217                                values.push(cmyk_component);
1218                            }
1219
1220                            self.input.skip_ws();
1221                        }
1222                        _ => {
1223                            unreachable!();
1224                        }
1225                    }
1226                }
1227
1228                if !is_one_of!(self, EOF, "/") && lower_fname == "device-cmyk" {
1229                    let cmyk_component = self.try_parse_variable_function(
1230                        |parser, _| Ok(Some(ComponentValue::CmykComponent(parser.parse()?))),
1231                        &mut has_variable,
1232                    )?;
1233
1234                    if let Some(cmyk_component) = cmyk_component {
1235                        values.push(cmyk_component);
1236                    }
1237
1238                    self.input.skip_ws();
1239                }
1240
1241                if is!(self, "/") {
1242                    values.push(ComponentValue::Delimiter(self.parse()?));
1243
1244                    self.input.skip_ws();
1245
1246                    let alpha_value = self.try_parse_variable_function(
1247                        |parser, has_variable_before| match cur!(parser) {
1248                            tok!("number") | tok!("percentage") => {
1249                                Ok(Some(ComponentValue::AlphaValue(parser.parse()?)))
1250                            }
1251                            Token::Function { value, .. } if is_math_function(value) => {
1252                                Ok(Some(ComponentValue::Function(parser.parse()?)))
1253                            }
1254                            tok!("ident") if !matches!(&*lower_fname, "device-cmyk") => {
1255                                let ident: Box<Ident> = parser.parse()?;
1256
1257                                if ident.value.eq_ignore_ascii_case("none") {
1258                                    Ok(Some(ComponentValue::Ident(ident)))
1259                                } else {
1260                                    Err(Error::new(
1261                                        ident.span,
1262                                        ErrorKind::Expected("'none' value of an ident token"),
1263                                    ))
1264                                }
1265                            }
1266                            _ => {
1267                                if !has_variable_before {
1268                                    Err(Error::new(
1269                                        parser.input.cur_span(),
1270                                        ErrorKind::Expected(
1271                                            "percentage, number, functions (math functions) or \
1272                                             ident (with 'none' value) token",
1273                                        ),
1274                                    ))
1275                                } else {
1276                                    Ok(None)
1277                                }
1278                            }
1279                        },
1280                        &mut has_variable,
1281                    )?;
1282
1283                    if let Some(alpha_value) = alpha_value {
1284                        values.push(alpha_value);
1285                    }
1286
1287                    self.input.skip_ws();
1288                }
1289            }
1290            "color" => {
1291                self.input.skip_ws();
1292
1293                let mut has_variable = false;
1294
1295                match cur!(self) {
1296                    Token::Ident { value, .. } if matches_eq_ignore_ascii_case!(value, "from") => {
1297                        values.push(ComponentValue::Ident(self.parse()?));
1298
1299                        self.input.skip_ws();
1300
1301                        let color = self.try_parse_variable_function(
1302                            |parser, _| Ok(Some(ComponentValue::Color(parser.parse()?))),
1303                            &mut has_variable,
1304                        )?;
1305
1306                        if let Some(color) = color {
1307                            values.push(color);
1308                        }
1309
1310                        self.input.skip_ws();
1311                    }
1312                    _ => {}
1313                }
1314
1315                let mut is_custom_params = false;
1316                let mut is_xyz = false;
1317
1318                let ident = self.try_parse_variable_function(
1319                    |parser, _| match cur!(parser) {
1320                        Token::Ident { value, .. } => {
1321                            if value.starts_with("--") && value.len() > 2 {
1322                                is_custom_params = true;
1323
1324                                Ok(Some(ComponentValue::DashedIdent(parser.parse()?)))
1325                            } else {
1326                                if matches_eq_ignore_ascii_case!(value, "xyz", "xyz-d50", "xyz-d65")
1327                                {
1328                                    is_xyz = true
1329                                } else {
1330                                    // There are predefined-rgb-params , but
1331                                    // For unknown, we don't return an error
1332                                    // to
1333                                    // continue to support invalid color,
1334                                    // because they fallback in browser
1335                                }
1336
1337                                Ok(Some(ComponentValue::Ident(parser.parse()?)))
1338                            }
1339                        }
1340                        _ => Err(Error::new(
1341                            parser.input.cur_span(),
1342                            ErrorKind::Expected("ident token"),
1343                        )),
1344                    },
1345                    &mut has_variable,
1346                )?;
1347
1348                if let Some(ident) = ident {
1349                    values.push(ident);
1350                }
1351
1352                self.input.skip_ws();
1353
1354                let number_or_percentage_or_none = self.try_parse_variable_function(
1355                    |parser, has_variable_before| match cur!(parser) {
1356                        tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
1357                        tok!("percentage") if !is_xyz => {
1358                            Ok(Some(ComponentValue::Percentage(parser.parse()?)))
1359                        }
1360                        Token::Function { value, .. } if is_math_function(value) => {
1361                            Ok(Some(ComponentValue::Function(parser.parse()?)))
1362                        }
1363                        tok!("ident") => {
1364                            let ident: Box<Ident> = parser.parse()?;
1365
1366                            if ident.value.eq_ignore_ascii_case("none") {
1367                                Ok(Some(ComponentValue::Ident(ident)))
1368                            } else {
1369                                Err(Error::new(
1370                                    ident.span,
1371                                    ErrorKind::Expected("'none' value of an ident token"),
1372                                ))
1373                            }
1374                        }
1375                        _ => {
1376                            if !has_variable_before {
1377                                Err(Error::new(
1378                                    parser.input.cur_span(),
1379                                    ErrorKind::Expected(
1380                                        "percentage, function (math functions) or ident (with \
1381                                         'none' value) token",
1382                                    ),
1383                                ))
1384                            } else {
1385                                Ok(None)
1386                            }
1387                        }
1388                    },
1389                    &mut has_variable,
1390                )?;
1391
1392                if let Some(number_or_percentage_or_none) = number_or_percentage_or_none {
1393                    values.push(number_or_percentage_or_none);
1394                }
1395
1396                self.input.skip_ws();
1397
1398                if is_custom_params {
1399                    loop {
1400                        if is!(self, EOF) {
1401                            break;
1402                        }
1403
1404                        let number_or_percentage_or_none = match cur!(self) {
1405                            tok!("number") => ComponentValue::Number(self.parse()?),
1406                            tok!("percentage") if !is_xyz => {
1407                                ComponentValue::Percentage(self.parse()?)
1408                            }
1409                            Token::Function { value, .. }
1410                                if is_math_function(value)
1411                                    || matches_eq_ignore_ascii_case!(
1412                                        value, "var", "env", "constant"
1413                                    ) =>
1414                            {
1415                                ComponentValue::Function(self.parse()?)
1416                            }
1417                            tok!("ident") => {
1418                                let ident: Box<Ident> = self.parse()?;
1419
1420                                if ident.value.eq_ignore_ascii_case("none") {
1421                                    ComponentValue::Ident(ident)
1422                                } else {
1423                                    return Err(Error::new(
1424                                        ident.span,
1425                                        ErrorKind::Expected("'none' value of an ident token"),
1426                                    ));
1427                                }
1428                            }
1429                            _ => {
1430                                break;
1431                            }
1432                        };
1433
1434                        values.push(number_or_percentage_or_none);
1435
1436                        self.input.skip_ws();
1437                    }
1438                } else {
1439                    let number_or_percentage_or_none = self.try_parse_variable_function(
1440                        |parser, has_variable_before| match cur!(parser) {
1441                            tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
1442                            tok!("percentage") if !is_xyz => {
1443                                Ok(Some(ComponentValue::Percentage(parser.parse()?)))
1444                            }
1445                            Token::Function { value, .. } if is_math_function(value) => {
1446                                Ok(Some(ComponentValue::Function(parser.parse()?)))
1447                            }
1448                            tok!("ident") => {
1449                                let ident: Box<Ident> = parser.parse()?;
1450
1451                                if ident.value.eq_ignore_ascii_case("none") {
1452                                    Ok(Some(ComponentValue::Ident(ident)))
1453                                } else {
1454                                    Err(Error::new(
1455                                        ident.span,
1456                                        ErrorKind::Expected("'none' value of an ident token"),
1457                                    ))
1458                                }
1459                            }
1460                            _ => {
1461                                if !has_variable_before {
1462                                    Err(Error::new(
1463                                        parser.input.cur_span(),
1464                                        ErrorKind::Expected(
1465                                            "percentage, function (math functions) or ident (with \
1466                                             'none' value) token",
1467                                        ),
1468                                    ))
1469                                } else {
1470                                    Ok(None)
1471                                }
1472                            }
1473                        },
1474                        &mut has_variable,
1475                    )?;
1476
1477                    if let Some(number_or_percentage_or_none) = number_or_percentage_or_none {
1478                        values.push(number_or_percentage_or_none);
1479                    }
1480
1481                    self.input.skip_ws();
1482
1483                    let number_or_percentage_or_none = self.try_parse_variable_function(
1484                        |parser, has_variable_before| match cur!(parser) {
1485                            tok!("number") => Ok(Some(ComponentValue::Number(parser.parse()?))),
1486                            tok!("percentage") if !is_xyz => {
1487                                Ok(Some(ComponentValue::Percentage(parser.parse()?)))
1488                            }
1489                            tok!("ident") => {
1490                                let ident: Box<Ident> = parser.parse()?;
1491
1492                                if ident.value.eq_ignore_ascii_case("none") {
1493                                    Ok(Some(ComponentValue::Ident(ident)))
1494                                } else {
1495                                    Err(Error::new(
1496                                        ident.span,
1497                                        ErrorKind::Expected("'none' value of an ident token"),
1498                                    ))
1499                                }
1500                            }
1501                            Token::Function { value, .. } if is_math_function(value) => {
1502                                Ok(Some(ComponentValue::Function(parser.parse()?)))
1503                            }
1504                            _ => {
1505                                if !has_variable_before {
1506                                    Err(Error::new(
1507                                        parser.input.cur_span(),
1508                                        ErrorKind::Expected(
1509                                            "percentage, function (math functions) or ident (with \
1510                                             'none' value) token",
1511                                        ),
1512                                    ))
1513                                } else {
1514                                    Ok(None)
1515                                }
1516                            }
1517                        },
1518                        &mut has_variable,
1519                    )?;
1520
1521                    if let Some(number_or_percentage_or_none) = number_or_percentage_or_none {
1522                        values.push(number_or_percentage_or_none);
1523                    }
1524
1525                    self.input.skip_ws();
1526                }
1527
1528                if is!(self, "/") {
1529                    values.push(ComponentValue::Delimiter(self.parse()?));
1530
1531                    self.input.skip_ws();
1532
1533                    let alpha_value = self.try_parse_variable_function(
1534                        |parser, has_variable_before| match cur!(parser) {
1535                            tok!("number") | tok!("percentage") => {
1536                                Ok(Some(ComponentValue::AlphaValue(parser.parse()?)))
1537                            }
1538                            Token::Function { value, .. } if is_math_function(value) => {
1539                                Ok(Some(ComponentValue::Function(parser.parse()?)))
1540                            }
1541                            tok!("ident") if !matches!(&*lower_fname, "device-cmyk") => {
1542                                let ident: Box<Ident> = parser.parse()?;
1543
1544                                if ident.value.eq_ignore_ascii_case("none") {
1545                                    Ok(Some(ComponentValue::Ident(ident)))
1546                                } else {
1547                                    Err(Error::new(
1548                                        ident.span,
1549                                        ErrorKind::Expected("'none' value of an ident token"),
1550                                    ))
1551                                }
1552                            }
1553                            _ => {
1554                                if !has_variable_before {
1555                                    Err(Error::new(
1556                                        parser.input.cur_span(),
1557                                        ErrorKind::Expected(
1558                                            "percentage, number, function (math functions) or \
1559                                             ident (with 'none' value) token",
1560                                        ),
1561                                    ))
1562                                } else {
1563                                    Ok(None)
1564                                }
1565                            }
1566                        },
1567                        &mut has_variable,
1568                    )?;
1569
1570                    if let Some(alpha_value) = alpha_value {
1571                        values.push(alpha_value);
1572                    }
1573
1574                    self.input.skip_ws();
1575                }
1576
1577                self.input.skip_ws();
1578            }
1579            "element" | "-moz-element" => {
1580                self.input.skip_ws();
1581
1582                let id_selector = self.try_parse_variable_function(
1583                    |parser, _| Ok(Some(ComponentValue::IdSelector(parser.parse()?))),
1584                    &mut false,
1585                )?;
1586
1587                if let Some(id_selector) = id_selector {
1588                    values.push(id_selector);
1589
1590                    self.input.skip_ws();
1591                }
1592            }
1593            "selector" if self.ctx.in_supports_at_rule => {
1594                self.input.skip_ws();
1595
1596                let selector = ComponentValue::ComplexSelector(self.parse()?);
1597
1598                values.push(selector);
1599
1600                self.input.skip_ws();
1601            }
1602            "layer" if self.ctx.in_import_at_rule => {
1603                self.input.skip_ws();
1604
1605                if is!(self, EOF) {
1606                    let span = self.input.cur_span();
1607
1608                    return Err(Error::new(
1609                        span,
1610                        ErrorKind::Expected(
1611                            "layer function inside @import expected to have exactly one ident \
1612                             argument",
1613                        ),
1614                    ));
1615                }
1616
1617                let layer_name = self.parse_as::<Box<LayerName>>()?;
1618
1619                values.push(ComponentValue::LayerName(layer_name));
1620
1621                self.input.skip_ws();
1622
1623                if !is!(self, EOF) {
1624                    let span = self.input.cur_span();
1625
1626                    return Err(Error::new(
1627                        span,
1628                        ErrorKind::Expected(
1629                            "layer function inside @import expected to have exactly one ident \
1630                             argument",
1631                        ),
1632                    ));
1633                }
1634            }
1635            "supports" if self.ctx.in_import_at_rule => {
1636                self.input.skip_ws();
1637
1638                if !is!(self, EOF) {
1639                    let state = self.input.state();
1640
1641                    match self.parse() {
1642                        Ok(declaration) => {
1643                            values.push(ComponentValue::Declaration(declaration));
1644
1645                            self.input.skip_ws();
1646                        }
1647                        Err(_) => {
1648                            self.input.reset(&state);
1649
1650                            let supports_conditions = self.parse()?;
1651
1652                            values.push(ComponentValue::SupportsCondition(supports_conditions));
1653                        }
1654                    }
1655                }
1656            }
1657            _ => loop {
1658                self.input.skip_ws();
1659
1660                if is!(self, EOF) {
1661                    break;
1662                }
1663
1664                let value = match self.try_parse(|p| p.parse_generic_value()) {
1665                    Some(v) => v,
1666                    None => {
1667                        if is_one_of!(self, ";", ":") || (self.config.legacy_ie && is!(self, "=")) {
1668                            let tok = self.input.bump().unwrap();
1669
1670                            ComponentValue::PreservedToken(Box::new(tok))
1671                        } else {
1672                            return Err(Error::new(
1673                                self.input.cur_span(),
1674                                ErrorKind::Expected("Declaration value"),
1675                            ));
1676                        }
1677                    }
1678                };
1679
1680                values.push(value);
1681            },
1682        };
1683
1684        Ok(values)
1685    }
1686
1687    fn try_parse_variable_function<F>(
1688        &mut self,
1689        mut fallback: F,
1690        has_before_variable: &mut bool,
1691    ) -> PResult<Option<ComponentValue>>
1692    where
1693        F: FnMut(&mut Parser<I>, bool) -> PResult<Option<ComponentValue>>,
1694    {
1695        if is!(self, EOF) {
1696            return Ok(None);
1697        }
1698
1699        match cur!(self) {
1700            Token::Function { value, .. }
1701                if matches_eq_ignore_ascii_case!(value, "var", "env", "constant") =>
1702            {
1703                *has_before_variable = true;
1704
1705                Ok(Some(ComponentValue::Function(self.parse()?)))
1706            }
1707            _ => fallback(self, *has_before_variable),
1708        }
1709    }
1710}
1711
1712impl<I> Parse<Delimiter> for Parser<I>
1713where
1714    I: ParserInput,
1715{
1716    fn parse(&mut self) -> PResult<Delimiter> {
1717        let span = self.input.cur_span();
1718
1719        if !is_one_of!(self, ",", "/", ";") {
1720            return Err(Error::new(
1721                span,
1722                ErrorKind::Expected("',', '/' or ';' delim token"),
1723            ));
1724        }
1725
1726        match cur!(self) {
1727            tok!(",") => {
1728                bump!(self);
1729
1730                return Ok(Delimiter {
1731                    span: span!(self, span.lo),
1732                    value: DelimiterValue::Comma,
1733                });
1734            }
1735            tok!("/") => {
1736                bump!(self);
1737
1738                return Ok(Delimiter {
1739                    span: span!(self, span.lo),
1740                    value: DelimiterValue::Solidus,
1741                });
1742            }
1743            tok!(";") => {
1744                bump!(self);
1745
1746                return Ok(Delimiter {
1747                    span: span!(self, span.lo),
1748                    value: DelimiterValue::Semicolon,
1749                });
1750            }
1751            _ => {
1752                unreachable!();
1753            }
1754        }
1755    }
1756}
1757
1758impl<I> Parse<Integer> for Parser<I>
1759where
1760    I: ParserInput,
1761{
1762    fn parse(&mut self) -> PResult<Integer> {
1763        let span = self.input.cur_span();
1764
1765        if !is!(self, Number) {
1766            return Err(Error::new(span, ErrorKind::ExpectedNumber));
1767        }
1768
1769        let value = bump!(self);
1770
1771        match value {
1772            Token::Number {
1773                value,
1774                raw,
1775                type_flag,
1776                ..
1777            } => {
1778                if type_flag == NumberType::Number {
1779                    return Err(Error::new(span, ErrorKind::Expected("integer type")));
1780                }
1781
1782                Ok(Integer {
1783                    span,
1784                    value: value.round() as i64,
1785                    raw: Some(raw),
1786                })
1787            }
1788            _ => {
1789                unreachable!()
1790            }
1791        }
1792    }
1793}
1794
1795impl<I> Parse<Number> for Parser<I>
1796where
1797    I: ParserInput,
1798{
1799    fn parse(&mut self) -> PResult<Number> {
1800        let span = self.input.cur_span();
1801
1802        if !is!(self, Number) {
1803            return Err(Error::new(span, ErrorKind::ExpectedNumber));
1804        }
1805
1806        let value = bump!(self);
1807
1808        match value {
1809            Token::Number { value, raw, .. } => Ok(Number {
1810                span,
1811                value,
1812                raw: Some(raw),
1813            }),
1814            _ => {
1815                unreachable!()
1816            }
1817        }
1818    }
1819}
1820
1821impl<I> Parse<CustomIdent> for Parser<I>
1822where
1823    I: ParserInput,
1824{
1825    fn parse(&mut self) -> PResult<CustomIdent> {
1826        let span = self.input.cur_span();
1827
1828        if !is!(self, Ident) {
1829            return Err(Error::new(span, ErrorKind::Expected("Ident")));
1830        }
1831
1832        match bump!(self) {
1833            Token::Ident { value, raw, .. } => {
1834                if matches_eq_ignore_ascii_case!(
1835                    value, "initial", "inherit", "unset", "revert", "default"
1836                ) {
1837                    return Err(Error::new(span, ErrorKind::InvalidCustomIdent(value)));
1838                }
1839
1840                Ok(CustomIdent {
1841                    span,
1842                    value,
1843                    raw: Some(raw),
1844                })
1845            }
1846            _ => {
1847                unreachable!()
1848            }
1849        }
1850    }
1851}
1852
1853impl<I> Parse<DashedIdent> for Parser<I>
1854where
1855    I: ParserInput,
1856{
1857    fn parse(&mut self) -> PResult<DashedIdent> {
1858        let span = self.input.cur_span();
1859
1860        if !is!(self, Ident) {
1861            return Err(Error::new(span, ErrorKind::Expected("Ident")));
1862        }
1863
1864        match bump!(self) {
1865            Token::Ident { value, raw, .. } => {
1866                if !value.starts_with("--") {
1867                    return Err(Error::new(
1868                        span,
1869                        ErrorKind::Expected("'--' at the start of dashed-ident"),
1870                    ));
1871                }
1872
1873                if value.len() < 3 {
1874                    return Err(Error::new(
1875                        span,
1876                        ErrorKind::Expected("dashed-ident must be at least 3 characters"),
1877                    ));
1878                }
1879
1880                Ok(DashedIdent {
1881                    span,
1882                    value: self.input.atom(&value[2..]),
1883                    raw: Some(raw),
1884                })
1885            }
1886            _ => {
1887                unreachable!()
1888            }
1889        }
1890    }
1891}
1892
1893impl<I> Parse<CustomPropertyName> for Parser<I>
1894where
1895    I: ParserInput,
1896{
1897    fn parse(&mut self) -> PResult<CustomPropertyName> {
1898        let span = self.input.cur_span();
1899
1900        if !is!(self, Ident) {
1901            return Err(Error::new(span, ErrorKind::Expected("Ident")));
1902        }
1903
1904        match bump!(self) {
1905            Token::Ident { value, raw, .. } => {
1906                if !value.starts_with("--") {
1907                    return Err(Error::new(
1908                        span,
1909                        ErrorKind::Expected("'--' at the start of custom property name"),
1910                    ));
1911                } else if &*value == "--" {
1912                    return Err(Error::new(
1913                        span,
1914                        ErrorKind::Expected("valid dashed, '--' is not valid custom property name"),
1915                    ));
1916                }
1917
1918                Ok(CustomPropertyName {
1919                    span,
1920                    value,
1921                    raw: Some(raw),
1922                })
1923            }
1924            _ => {
1925                unreachable!()
1926            }
1927        }
1928    }
1929}
1930
1931impl<I> Parse<Ident> for Parser<I>
1932where
1933    I: ParserInput,
1934{
1935    fn parse(&mut self) -> PResult<Ident> {
1936        let span = self.input.cur_span();
1937
1938        if !is!(self, Ident) {
1939            return Err(Error::new(span, ErrorKind::Expected("Ident")));
1940        }
1941
1942        match bump!(self) {
1943            Token::Ident { value, raw, .. } => Ok(Ident {
1944                span,
1945                value,
1946                raw: Some(raw),
1947            }),
1948            _ => {
1949                unreachable!()
1950            }
1951        }
1952    }
1953}
1954
1955impl<I> Parse<Dimension> for Parser<I>
1956where
1957    I: ParserInput,
1958{
1959    fn parse(&mut self) -> PResult<Dimension> {
1960        let span = self.input.cur_span();
1961
1962        if !is!(self, Dimension) {
1963            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
1964        }
1965
1966        match cur!(self) {
1967            Token::Dimension {
1968                dimension: dimension_token,
1969            } => {
1970                match &dimension_token.unit {
1971                    // <length>
1972                    unit if is_length_unit(unit)
1973                        || (self.ctx.in_container_at_rule && is_container_lengths_unit(unit)) =>
1974                    {
1975                        Ok(Dimension::Length(self.parse()?))
1976                    }
1977                    // <angle>
1978                    unit if is_angle_unit(unit) => Ok(Dimension::Angle(self.parse()?)),
1979                    // <time>
1980                    unit if is_time_unit(unit) => Ok(Dimension::Time(self.parse()?)),
1981                    // <frequency>
1982                    unit if is_frequency_unit(unit) => Ok(Dimension::Frequency(self.parse()?)),
1983                    // <resolution>
1984                    unit if is_resolution_unit(unit) => Ok(Dimension::Resolution(self.parse()?)),
1985                    // <flex>
1986                    unit if is_flex_unit(unit) => Ok(Dimension::Flex(self.parse()?)),
1987                    _ => Ok(Dimension::UnknownDimension(self.parse()?)),
1988                }
1989            }
1990            _ => {
1991                unreachable!()
1992            }
1993        }
1994    }
1995}
1996
1997impl<I> Parse<Length> for Parser<I>
1998where
1999    I: ParserInput,
2000{
2001    fn parse(&mut self) -> PResult<Length> {
2002        let span = self.input.cur_span();
2003
2004        if !is!(self, Dimension) {
2005            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2006        }
2007
2008        match bump!(self) {
2009            Token::Dimension {
2010                dimension: dimension_token,
2011            } => {
2012                let DimensionToken {
2013                    value,
2014                    unit,
2015                    raw_value,
2016                    raw_unit,
2017                    ..
2018                } = *dimension_token;
2019
2020                // TODO validate
2021
2022                let unit_len = raw_unit.len() as u32;
2023
2024                Ok(Length {
2025                    span,
2026                    value: Number {
2027                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2028                        value,
2029                        raw: Some(raw_value),
2030                    },
2031                    unit: Ident {
2032                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2033                        value: unit,
2034                        raw: Some(raw_unit),
2035                    },
2036                })
2037            }
2038            _ => {
2039                unreachable!()
2040            }
2041        }
2042    }
2043}
2044
2045impl<I> Parse<Angle> for Parser<I>
2046where
2047    I: ParserInput,
2048{
2049    fn parse(&mut self) -> PResult<Angle> {
2050        let span = self.input.cur_span();
2051
2052        if !is!(self, Dimension) {
2053            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2054        }
2055
2056        match bump!(self) {
2057            Token::Dimension {
2058                dimension: dimension_token,
2059            } => {
2060                let DimensionToken {
2061                    value,
2062                    unit,
2063                    raw_value,
2064                    raw_unit,
2065                    ..
2066                } = *dimension_token;
2067
2068                if !is_angle_unit(&unit) {
2069                    return Err(Error::new(
2070                        span,
2071                        ErrorKind::Expected("'deg', 'grad', 'rad' or 'turn' units"),
2072                    ));
2073                }
2074
2075                let unit_len = raw_unit.len() as u32;
2076
2077                Ok(Angle {
2078                    span,
2079                    value: Number {
2080                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2081                        value,
2082                        raw: Some(raw_value),
2083                    },
2084                    unit: Ident {
2085                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2086                        value: unit,
2087                        raw: Some(raw_unit),
2088                    },
2089                })
2090            }
2091            _ => {
2092                unreachable!()
2093            }
2094        }
2095    }
2096}
2097
2098impl<I> Parse<Time> for Parser<I>
2099where
2100    I: ParserInput,
2101{
2102    fn parse(&mut self) -> PResult<Time> {
2103        let span = self.input.cur_span();
2104
2105        if !is!(self, Dimension) {
2106            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2107        }
2108
2109        match bump!(self) {
2110            Token::Dimension {
2111                dimension: dimension_token,
2112            } => {
2113                let DimensionToken {
2114                    value,
2115                    unit,
2116                    raw_value,
2117                    raw_unit,
2118                    ..
2119                } = *dimension_token;
2120
2121                if !is_time_unit(&unit) {
2122                    return Err(Error::new(span, ErrorKind::Expected("'s' or 'ms' units")));
2123                }
2124
2125                let unit_len = raw_unit.len() as u32;
2126
2127                Ok(Time {
2128                    span,
2129                    value: Number {
2130                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2131                        value,
2132                        raw: Some(raw_value),
2133                    },
2134                    unit: Ident {
2135                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2136                        value: unit,
2137                        raw: Some(raw_unit),
2138                    },
2139                })
2140            }
2141            _ => {
2142                unreachable!()
2143            }
2144        }
2145    }
2146}
2147
2148impl<I> Parse<Frequency> for Parser<I>
2149where
2150    I: ParserInput,
2151{
2152    fn parse(&mut self) -> PResult<Frequency> {
2153        let span = self.input.cur_span();
2154
2155        if !is!(self, Dimension) {
2156            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2157        }
2158
2159        match bump!(self) {
2160            Token::Dimension {
2161                dimension: dimension_token,
2162            } => {
2163                let DimensionToken {
2164                    value,
2165                    unit,
2166                    raw_value,
2167                    raw_unit,
2168                    ..
2169                } = *dimension_token;
2170
2171                if !is_frequency_unit(&unit) {
2172                    return Err(Error::new(span, ErrorKind::Expected("'Hz' or 'kHz' units")));
2173                }
2174
2175                let unit_len = raw_unit.len() as u32;
2176
2177                Ok(Frequency {
2178                    span,
2179                    value: Number {
2180                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2181                        value,
2182                        raw: Some(raw_value),
2183                    },
2184                    unit: Ident {
2185                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2186                        value: unit,
2187                        raw: Some(raw_unit),
2188                    },
2189                })
2190            }
2191            _ => {
2192                unreachable!()
2193            }
2194        }
2195    }
2196}
2197
2198impl<I> Parse<Resolution> for Parser<I>
2199where
2200    I: ParserInput,
2201{
2202    fn parse(&mut self) -> PResult<Resolution> {
2203        let span = self.input.cur_span();
2204
2205        if !is!(self, Dimension) {
2206            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2207        }
2208
2209        match bump!(self) {
2210            Token::Dimension {
2211                dimension: dimension_token,
2212            } => {
2213                let DimensionToken {
2214                    value,
2215                    unit,
2216                    raw_value,
2217                    raw_unit,
2218                    ..
2219                } = *dimension_token;
2220
2221                if !is_resolution_unit(&unit) {
2222                    return Err(Error::new(
2223                        span,
2224                        ErrorKind::Expected("'dpi', 'dpcm', 'dppx' or 'x' units"),
2225                    ));
2226                }
2227
2228                let unit_len = raw_unit.len() as u32;
2229
2230                Ok(Resolution {
2231                    span,
2232                    value: Number {
2233                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2234                        value,
2235                        raw: Some(raw_value),
2236                    },
2237                    unit: Ident {
2238                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2239                        value: unit,
2240                        raw: Some(raw_unit),
2241                    },
2242                })
2243            }
2244            _ => {
2245                unreachable!()
2246            }
2247        }
2248    }
2249}
2250
2251impl<I> Parse<Flex> for Parser<I>
2252where
2253    I: ParserInput,
2254{
2255    fn parse(&mut self) -> PResult<Flex> {
2256        let span = self.input.cur_span();
2257
2258        if !is!(self, Dimension) {
2259            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2260        }
2261
2262        match bump!(self) {
2263            Token::Dimension {
2264                dimension: dimension_token,
2265            } => {
2266                let DimensionToken {
2267                    value,
2268                    unit,
2269                    raw_value,
2270                    raw_unit,
2271                    ..
2272                } = *dimension_token;
2273
2274                if !is_flex_unit(&unit) {
2275                    return Err(Error::new(span, ErrorKind::Expected("'fr' unit")));
2276                }
2277
2278                let unit_len = raw_unit.len() as u32;
2279
2280                Ok(Flex {
2281                    span,
2282                    value: Number {
2283                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2284                        value,
2285                        raw: Some(raw_value),
2286                    },
2287                    unit: Ident {
2288                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2289                        value: unit,
2290                        raw: Some(raw_unit),
2291                    },
2292                })
2293            }
2294            _ => {
2295                unreachable!()
2296            }
2297        }
2298    }
2299}
2300
2301impl<I> Parse<UnknownDimension> for Parser<I>
2302where
2303    I: ParserInput,
2304{
2305    fn parse(&mut self) -> PResult<UnknownDimension> {
2306        let span = self.input.cur_span();
2307
2308        if !is!(self, Dimension) {
2309            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2310        }
2311
2312        match bump!(self) {
2313            Token::Dimension {
2314                dimension: dimension_token,
2315            } => {
2316                let DimensionToken {
2317                    value,
2318                    unit,
2319                    raw_value,
2320                    raw_unit,
2321                    ..
2322                } = *dimension_token;
2323
2324                let unit_len = raw_unit.len() as u32;
2325
2326                Ok(UnknownDimension {
2327                    span,
2328                    value: Number {
2329                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2330                        value,
2331                        raw: Some(raw_value),
2332                    },
2333                    unit: Ident {
2334                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2335                        value: self.input.atom(unit.to_lowercase()),
2336                        raw: Some(raw_unit),
2337                    },
2338                })
2339            }
2340            _ => {
2341                unreachable!()
2342            }
2343        }
2344    }
2345}
2346
2347impl<I> Parse<Color> for Parser<I>
2348where
2349    I: ParserInput,
2350{
2351    fn parse(&mut self) -> PResult<Color> {
2352        let span = self.input.cur_span();
2353
2354        match cur!(self) {
2355            // currentcolor | <system-color>
2356            Token::Ident { value, .. }
2357                if value.as_ref().eq_ignore_ascii_case("currentcolor")
2358                    || is_system_color(value) =>
2359            {
2360                Ok(Color::CurrentColorOrSystemColor(self.parse()?))
2361            }
2362            // <device-cmyk()>
2363            Token::Function { value, .. } if value.as_ref().eq_ignore_ascii_case("device-cmyk") => {
2364                Ok(Color::Function(self.parse()?))
2365            }
2366            // <absolute-color-base>
2367            _ => match self.parse() {
2368                Ok(absolute_color_base) => Ok(Color::AbsoluteColorBase(absolute_color_base)),
2369                Err(_) => {
2370                    return Err(Error::new(
2371                        span,
2372                        ErrorKind::Expected(
2373                            "hash, ident (with named color, system color, 'transparent' or \
2374                             'currentColor' value) or function (with color function name) token",
2375                        ),
2376                    ));
2377                }
2378            },
2379        }
2380    }
2381}
2382
2383impl<I> Parse<AbsoluteColorBase> for Parser<I>
2384where
2385    I: ParserInput,
2386{
2387    fn parse(&mut self) -> PResult<AbsoluteColorBase> {
2388        let span = self.input.cur_span();
2389
2390        match cur!(self) {
2391            tok!("#") => Ok(AbsoluteColorBase::HexColor(self.parse()?)),
2392            Token::Ident { value, .. } => {
2393                if !(is_named_color(value) || value.as_ref().eq_ignore_ascii_case("transparent")) {
2394                    let span = self.input.cur_span();
2395
2396                    return Err(Error::new(
2397                        span,
2398                        ErrorKind::Expected("known named color or 'transparent' keyword"),
2399                    ));
2400                }
2401
2402                Ok(AbsoluteColorBase::NamedColorOrTransparent(self.parse()?))
2403            }
2404            Token::Function { value, .. } if is_absolute_color_base_function(value) => {
2405                Ok(AbsoluteColorBase::Function(self.parse()?))
2406            }
2407            _ => {
2408                return Err(Error::new(
2409                    span,
2410                    ErrorKind::Expected(
2411                        "hash, ident (with named color or 'transparent' value) or function (with \
2412                         color function name) token",
2413                    ),
2414                ));
2415            }
2416        }
2417    }
2418}
2419
2420impl<I> Parse<HexColor> for Parser<I>
2421where
2422    I: ParserInput,
2423{
2424    fn parse(&mut self) -> PResult<HexColor> {
2425        let span = self.input.cur_span();
2426
2427        if !is!(self, "#") {
2428            return Err(Error::new(span, ErrorKind::Expected("hash token")));
2429        }
2430
2431        match bump!(self) {
2432            Token::Hash { value, raw, .. } => {
2433                if value.chars().any(|x| !x.is_ascii_hexdigit()) {
2434                    return Err(Error::new(
2435                        span,
2436                        ErrorKind::Unexpected("character in hex color"),
2437                    ));
2438                }
2439
2440                Ok(HexColor {
2441                    span,
2442                    value,
2443                    raw: Some(raw),
2444                })
2445            }
2446            _ => {
2447                unreachable!()
2448            }
2449        }
2450    }
2451}
2452
2453impl<I> Parse<AlphaValue> for Parser<I>
2454where
2455    I: ParserInput,
2456{
2457    fn parse(&mut self) -> PResult<AlphaValue> {
2458        if !is_one_of!(self, "percentage", "number") {
2459            let span = self.input.cur_span();
2460
2461            return Err(Error::new(
2462                span,
2463                ErrorKind::Expected("percentage or number token"),
2464            ));
2465        }
2466
2467        match cur!(self) {
2468            tok!("percentage") => Ok(AlphaValue::Percentage(self.parse()?)),
2469            tok!("number") => Ok(AlphaValue::Number(self.parse()?)),
2470            _ => {
2471                unreachable!()
2472            }
2473        }
2474    }
2475}
2476
2477impl<I> Parse<Hue> for Parser<I>
2478where
2479    I: ParserInput,
2480{
2481    fn parse(&mut self) -> PResult<Hue> {
2482        if !is_one_of!(self, "number", "dimension") {
2483            let span = self.input.cur_span();
2484
2485            return Err(Error::new(
2486                span,
2487                ErrorKind::Expected("number or dimension token"),
2488            ));
2489        }
2490
2491        match cur!(self) {
2492            tok!("number") => Ok(Hue::Number(self.parse()?)),
2493            tok!("dimension") => Ok(Hue::Angle(self.parse()?)),
2494            _ => {
2495                unreachable!()
2496            }
2497        }
2498    }
2499}
2500
2501impl<I> Parse<CmykComponent> for Parser<I>
2502where
2503    I: ParserInput,
2504{
2505    fn parse(&mut self) -> PResult<CmykComponent> {
2506        if !is_one_of!(self, "number", "percentage", "function") {
2507            let span = self.input.cur_span();
2508
2509            return Err(Error::new(
2510                span,
2511                ErrorKind::Expected("number, function or percentage token"),
2512            ));
2513        }
2514
2515        match cur!(self) {
2516            tok!("number") => Ok(CmykComponent::Number(self.parse()?)),
2517            tok!("percentage") => Ok(CmykComponent::Percentage(self.parse()?)),
2518            Token::Function { value, .. } => {
2519                if !is_math_function(value) {
2520                    let span = self.input.cur_span();
2521
2522                    return Err(Error::new(span, ErrorKind::Expected("math function token")));
2523                }
2524
2525                Ok(CmykComponent::Function(self.parse()?))
2526            }
2527            _ => {
2528                unreachable!()
2529            }
2530        }
2531    }
2532}
2533
2534impl<I> Parse<Percentage> for Parser<I>
2535where
2536    I: ParserInput,
2537{
2538    fn parse(&mut self) -> PResult<Percentage> {
2539        let span = self.input.cur_span();
2540
2541        if !is!(self, Percentage) {
2542            return Err(Error::new(span, ErrorKind::Expected("percentage token")));
2543        }
2544
2545        match bump!(self) {
2546            Token::Percentage { value, raw } => {
2547                let value = Number {
2548                    span: Span::new(span.lo, span.hi - BytePos(1)),
2549                    value,
2550                    raw: Some(raw),
2551                };
2552
2553                Ok(Percentage { span, value })
2554            }
2555            _ => {
2556                unreachable!()
2557            }
2558        }
2559    }
2560}
2561
2562impl<I> Parse<Str> for Parser<I>
2563where
2564    I: ParserInput,
2565{
2566    fn parse(&mut self) -> PResult<Str> {
2567        let span = self.input.cur_span();
2568
2569        if !is!(self, "string") {
2570            return Err(Error::new(span, ErrorKind::Expected("string token")));
2571        }
2572
2573        match bump!(self) {
2574            Token::String { value, raw } => Ok(Str {
2575                span,
2576                value,
2577                raw: Some(raw),
2578            }),
2579            _ => {
2580                unreachable!()
2581            }
2582        }
2583    }
2584}
2585
2586impl<I> Parse<Url> for Parser<I>
2587where
2588    I: ParserInput,
2589{
2590    fn parse(&mut self) -> PResult<Url> {
2591        let span = self.input.cur_span();
2592
2593        if !is_one_of!(self, Url, Function) {
2594            return Err(Error::new(
2595                span,
2596                ErrorKind::Expected("url or function (with 'url' or 'src' name) token"),
2597            ));
2598        }
2599
2600        match bump!(self) {
2601            Token::Url { value, raw } => {
2602                let name_length = raw.0.len() as u32;
2603                let name = Ident {
2604                    span: Span::new(span.lo, span.lo + BytePos(name_length)),
2605                    value: self.input.atom("url"),
2606                    raw: Some(raw.0),
2607                };
2608                let value = Some(Box::new(UrlValue::Raw(UrlValueRaw {
2609                    span: Span::new(span.lo + BytePos(name_length + 1), span.hi - BytePos(1)),
2610                    value,
2611                    raw: Some(raw.1),
2612                })));
2613
2614                Ok(Url {
2615                    span: span!(self, span.lo),
2616                    name,
2617                    value,
2618                    modifiers: None,
2619                })
2620            }
2621            Token::Function {
2622                value: function_name,
2623                raw: raw_function_name,
2624            } => {
2625                if !matches_eq_ignore_ascii_case!(function_name, "url", "src") {
2626                    return Err(Error::new(
2627                        span,
2628                        ErrorKind::Expected("'url' or 'src' name of a function token"),
2629                    ));
2630                }
2631
2632                let name = Ident {
2633                    span: Span::new(span.lo, span.hi - BytePos(1)),
2634                    value: function_name,
2635                    raw: Some(raw_function_name),
2636                };
2637
2638                self.input.skip_ws();
2639
2640                let value = match cur!(self) {
2641                    tok!("string") => Some(Box::new(UrlValue::Str(self.parse()?))),
2642                    _ => None,
2643                };
2644
2645                self.input.skip_ws();
2646
2647                let mut modifiers = Vec::new();
2648
2649                loop {
2650                    if is!(self, ")") {
2651                        break;
2652                    }
2653
2654                    match cur!(self) {
2655                        tok!("ident") => {
2656                            modifiers.push(UrlModifier::Ident(self.parse()?));
2657                        }
2658                        tok!("function") => {
2659                            modifiers.push(UrlModifier::Function(self.parse()?));
2660                        }
2661                        _ => {
2662                            let span = self.input.cur_span();
2663
2664                            return Err(Error::new(span, ErrorKind::Expected("ident or function")));
2665                        }
2666                    }
2667
2668                    self.input.skip_ws();
2669                }
2670
2671                expect!(self, ")");
2672
2673                Ok(Url {
2674                    span: span!(self, span.lo),
2675                    name,
2676                    value,
2677                    modifiers: Some(modifiers),
2678                })
2679            }
2680            _ => {
2681                unreachable!()
2682            }
2683        }
2684    }
2685}
2686
2687// <urange> =
2688//   u '+' <ident-token> '?'* |
2689//   u <dimension-token> '?'* |
2690//   u <number-token> '?'* |
2691//   u <number-token> <dimension-token> |
2692//   u <number-token> <number-token> |
2693//   u '+' '?'+
2694impl<I> Parse<UnicodeRange> for Parser<I>
2695where
2696    I: ParserInput,
2697{
2698    fn parse(&mut self) -> PResult<UnicodeRange> {
2699        let span = self.input.cur_span();
2700        let mut unicode_range = String::new();
2701
2702        // should start with `u` or `U`
2703        match cur!(self) {
2704            Token::Ident { value, .. } if matches_eq_ignore_ascii_case!(value, "u") => {
2705                let u = match bump!(self) {
2706                    Token::Ident { value, .. } => value,
2707                    _ => {
2708                        unreachable!();
2709                    }
2710                };
2711
2712                unicode_range.push_str(&u);
2713            }
2714            _ => {
2715                return Err(Error::new(span, ErrorKind::Expected("'u' ident token")));
2716            }
2717        };
2718
2719        match cur!(self) {
2720            // u '+' <ident-token> '?'*
2721            // u '+' '?'+
2722            Token::Delim { value } if *value == '+' => {
2723                let plus = match bump!(self) {
2724                    Token::Delim { value } => value,
2725                    _ => {
2726                        unreachable!();
2727                    }
2728                };
2729
2730                unicode_range.push(plus);
2731
2732                if is!(self, Ident) {
2733                    let ident = match bump!(self) {
2734                        Token::Ident { value, .. } => value,
2735                        _ => {
2736                            unreachable!();
2737                        }
2738                    };
2739
2740                    unicode_range.push_str(&ident);
2741
2742                    loop {
2743                        if !is!(self, "?") {
2744                            break;
2745                        }
2746
2747                        let question = match bump!(self) {
2748                            Token::Delim { value } => value,
2749                            _ => {
2750                                unreachable!();
2751                            }
2752                        };
2753
2754                        unicode_range.push(question);
2755                    }
2756                } else {
2757                    let question = match bump!(self) {
2758                        Token::Delim { value } if value == '?' => value,
2759                        _ => {
2760                            return Err(Error::new(span, ErrorKind::Expected("'?' delim token")));
2761                        }
2762                    };
2763
2764                    unicode_range.push(question);
2765
2766                    loop {
2767                        if !is!(self, "?") {
2768                            break;
2769                        }
2770
2771                        let question = match bump!(self) {
2772                            Token::Delim { value } => value,
2773                            _ => {
2774                                unreachable!();
2775                            }
2776                        };
2777
2778                        unicode_range.push(question);
2779                    }
2780                }
2781            }
2782            // u <number-token> '?'*
2783            // u <number-token> <dimension-token>
2784            // u <number-token> <number-token>
2785            tok!("number") => {
2786                let number = match bump!(self) {
2787                    Token::Number { raw, .. } => raw,
2788                    _ => {
2789                        unreachable!();
2790                    }
2791                };
2792
2793                unicode_range.push_str(&number);
2794
2795                if !is!(self, EOF) {
2796                    match cur!(self) {
2797                        tok!("?") => {
2798                            let question = match bump!(self) {
2799                                Token::Delim { value } => value,
2800                                _ => {
2801                                    unreachable!();
2802                                }
2803                            };
2804
2805                            unicode_range.push(question);
2806
2807                            loop {
2808                                if !is!(self, "?") {
2809                                    break;
2810                                }
2811
2812                                let question = match bump!(self) {
2813                                    Token::Delim { value } => value,
2814                                    _ => {
2815                                        unreachable!();
2816                                    }
2817                                };
2818
2819                                unicode_range.push(question);
2820                            }
2821                        }
2822                        tok!("dimension") => {
2823                            let raw = match bump!(self) {
2824                                Token::Dimension {
2825                                    dimension: dimension_token,
2826                                } => (dimension_token.raw_value, dimension_token.raw_unit),
2827                                _ => {
2828                                    unreachable!();
2829                                }
2830                            };
2831
2832                            unicode_range.push_str(&raw.0);
2833                            unicode_range.push_str(&raw.1);
2834                        }
2835                        tok!("number") => {
2836                            let number = match bump!(self) {
2837                                Token::Number { raw, .. } => raw,
2838                                _ => {
2839                                    unreachable!();
2840                                }
2841                            };
2842
2843                            unicode_range.push_str(&number);
2844                        }
2845                        _ => {}
2846                    }
2847                }
2848            }
2849            // u <dimension-token> '?'*
2850            tok!("dimension") => {
2851                let raw = match bump!(self) {
2852                    Token::Dimension {
2853                        dimension: dimension_token,
2854                    } => (dimension_token.raw_value, dimension_token.raw_unit),
2855                    _ => {
2856                        unreachable!();
2857                    }
2858                };
2859
2860                unicode_range.push_str(&raw.0);
2861                unicode_range.push_str(&raw.1);
2862
2863                loop {
2864                    if !is!(self, "?") {
2865                        break;
2866                    }
2867
2868                    let question = match bump!(self) {
2869                        Token::Delim { value } => value,
2870                        _ => {
2871                            unreachable!();
2872                        }
2873                    };
2874
2875                    unicode_range.push(question);
2876                }
2877            }
2878            _ => {
2879                return Err(Error::new(
2880                    span,
2881                    ErrorKind::Expected("dimension, number or '?' delim token"),
2882                ));
2883            }
2884        }
2885
2886        let mut chars = unicode_range.chars();
2887
2888        // 1. Skipping the first u token, concatenate the representations of all the
2889        // tokens in the production together. Let this be text.
2890        chars.next();
2891
2892        // 2. If the first character of text is U+002B PLUS SIGN, consume it. Otherwise,
2893        // this is an invalid <urange>, and this algorithm must exit.
2894        let mut next = chars.next();
2895
2896        if next != Some('+') {
2897            return Err(Error::new(
2898                span,
2899                ErrorKind::Expected("'+' character after 'u' in unicode range"),
2900            ));
2901        } else {
2902            next = chars.next();
2903        }
2904
2905        // 3. Consume as many hex digits from text as possible. then consume as many
2906        // U+003F QUESTION MARK (?) code points as possible. If zero code points
2907        // were consumed, or more than six code points were consumed, this is an
2908        // invalid <urange>, and this algorithm must exit.
2909        let mut start = String::new();
2910
2911        loop {
2912            match next {
2913                Some(c) if c.is_ascii_digit() => {
2914                    start.push(c);
2915
2916                    next = chars.next();
2917                }
2918                Some(c @ 'A'..='F') | Some(c @ 'a'..='f') => {
2919                    start.push(c);
2920
2921                    next = chars.next();
2922                }
2923                _ => {
2924                    break;
2925                }
2926            }
2927        }
2928
2929        let mut has_question_mark = false;
2930
2931        while let Some(c @ '?') = next {
2932            has_question_mark = true;
2933
2934            start.push(c);
2935
2936            next = chars.next();
2937        }
2938
2939        let len = start.len();
2940
2941        if len == 0 || len > 6 {
2942            return Err(Error::new(
2943                span,
2944                ErrorKind::Expected(
2945                    "valid length (minimum 1 or maximum 6 hex digits) in the start of unicode \
2946                     range",
2947                ),
2948            ));
2949        }
2950
2951        // If any U+003F QUESTION MARK (?) code points were consumed, then:
2952        if has_question_mark {
2953            // 1. If there are any code points left in text, this is an invalid <urange>,
2954            // and this algorithm must exit.
2955            if next.is_some() {
2956                return Err(Error::new(
2957                    span,
2958                    ErrorKind::Expected("no characters after '?' in unicode range"),
2959                ));
2960            }
2961
2962            // 2. Interpret the consumed code points
2963            // as a hexadecimal number, with the U+003F QUESTION MARK (?) code points
2964            // replaced by U+0030 DIGIT ZERO (0) code points. This is the start value.
2965            //
2966            // 3. Interpret the consumed code points as a hexadecimal number again, with the
2967            // U+003F QUESTION MARK (?) code points replaced by U+0046 LATIN CAPITAL LETTER
2968            // F (F) code points. This is the end value.
2969            //
2970
2971            // 4. Exit this algorithm.
2972            return Ok(UnicodeRange {
2973                span: span!(self, span.lo),
2974                start: self.input.atom(start),
2975                end: None,
2976                raw: Some(self.input.atom(unicode_range)),
2977            });
2978        }
2979
2980        // Otherwise, interpret the consumed code points as a hexadecimal number. This
2981        // is the start value.
2982
2983        // 4. If there are no code points left in text, The end value is the same as the
2984        // start value. Exit this algorithm.
2985        if next.is_none() {
2986            return Ok(UnicodeRange {
2987                span: span!(self, span.lo),
2988                start: self.input.atom(start),
2989                end: None,
2990                raw: Some(self.input.atom(unicode_range)),
2991            });
2992        }
2993
2994        // 5. If the next code point in text is U+002D HYPHEN-MINUS (-), consume it.
2995        // Otherwise, this is an invalid <urange>, and this algorithm must exit.
2996        if next != Some('-') {
2997            return Err(Error::new(
2998                span,
2999                ErrorKind::Expected("'-' between start and end in unicode range"),
3000            ));
3001        } else {
3002            next = chars.next();
3003        }
3004
3005        // 6. Consume as many hex digits as possible from text.
3006        // If zero hex digits were consumed, or more than 6 hex digits were consumed,
3007        // this is an invalid <urange>, and this algorithm must exit. If there are any
3008        // code points left in text, this is an invalid <urange>, and this algorithm
3009        // must exit.
3010        let mut end = String::new();
3011
3012        loop {
3013            match next {
3014                Some(c) if c.is_ascii_digit() => {
3015                    end.push(c);
3016                    next = chars.next();
3017                }
3018                Some(c @ 'A'..='F') | Some(c @ 'a'..='f') => {
3019                    end.push(c);
3020                    next = chars.next();
3021                }
3022                _ => {
3023                    break;
3024                }
3025            }
3026        }
3027
3028        let len = end.len();
3029
3030        if len == 0 || len > 6 {
3031            return Err(Error::new(
3032                span,
3033                ErrorKind::Expected(
3034                    "valid length (minimum 1 or maximum 6 hex digits) in the end of unicode range",
3035                ),
3036            ));
3037        }
3038
3039        if chars.next().is_some() {
3040            return Err(Error::new(
3041                span,
3042                ErrorKind::Expected("no characters after end in unicode range"),
3043            ));
3044        }
3045
3046        return Ok(UnicodeRange {
3047            span: span!(self, span.lo),
3048            start: self.input.atom(start),
3049            end: Some(self.input.atom(end)),
3050            raw: Some(self.input.atom(unicode_range)),
3051        });
3052    }
3053}
3054
3055impl<I> Parse<CalcSum> for Parser<I>
3056where
3057    I: ParserInput,
3058{
3059    fn parse(&mut self) -> PResult<CalcSum> {
3060        let start = self.input.cur_span().lo;
3061        let mut expressions = Vec::new();
3062        let calc_product = CalcProductOrOperator::Product(self.parse()?);
3063        let mut end = match calc_product {
3064            CalcProductOrOperator::Product(ref calc_product) => calc_product.span.hi,
3065            _ => {
3066                unreachable!();
3067            }
3068        };
3069
3070        expressions.push(calc_product);
3071
3072        loop {
3073            self.input.skip_ws();
3074
3075            if is!(self, EOF) {
3076                break;
3077            }
3078
3079            match cur!(self) {
3080                tok!("+") | tok!("-") => {
3081                    let operator = CalcProductOrOperator::Operator(self.parse()?);
3082
3083                    expressions.push(operator);
3084
3085                    self.input.skip_ws();
3086
3087                    let calc_product = CalcProductOrOperator::Product(self.parse()?);
3088
3089                    end = match calc_product {
3090                        CalcProductOrOperator::Product(ref calc_product) => calc_product.span.hi,
3091                        _ => {
3092                            unreachable!();
3093                        }
3094                    };
3095
3096                    expressions.push(calc_product);
3097                }
3098                _ => {
3099                    break;
3100                }
3101            }
3102        }
3103
3104        Ok(CalcSum {
3105            span: Span::new(start, end),
3106            expressions,
3107        })
3108    }
3109}
3110
3111impl<I> Parse<CalcProduct> for Parser<I>
3112where
3113    I: ParserInput,
3114{
3115    fn parse(&mut self) -> PResult<CalcProduct> {
3116        let start = self.input.cur_span().lo;
3117        let mut expressions = Vec::new();
3118        let calc_value = CalcValueOrOperator::Value(self.parse()?);
3119        let mut end = match calc_value {
3120            CalcValueOrOperator::Value(ref calc_value) => match calc_value {
3121                CalcValue::Number(item) => item.span.hi,
3122                CalcValue::Percentage(item) => item.span.hi,
3123                CalcValue::Constant(item) => item.span.hi,
3124                CalcValue::Sum(item) => item.span.hi,
3125                CalcValue::Function(item) => item.span.hi,
3126                CalcValue::Dimension(item) => match item {
3127                    Dimension::Length(item) => item.span.hi,
3128                    Dimension::Angle(item) => item.span.hi,
3129                    Dimension::Time(item) => item.span.hi,
3130                    Dimension::Frequency(item) => item.span.hi,
3131                    Dimension::Resolution(item) => item.span.hi,
3132                    Dimension::Flex(item) => item.span.hi,
3133                    Dimension::UnknownDimension(item) => item.span.hi,
3134                },
3135            },
3136            _ => {
3137                unreachable!();
3138            }
3139        };
3140
3141        expressions.push(calc_value);
3142
3143        loop {
3144            self.input.skip_ws();
3145
3146            if is!(self, EOF) {
3147                break;
3148            }
3149
3150            match cur!(self) {
3151                tok!("*") | tok!("/") => {
3152                    let operator = CalcValueOrOperator::Operator(self.parse()?);
3153
3154                    expressions.push(operator);
3155
3156                    self.input.skip_ws();
3157
3158                    let calc_value = CalcValueOrOperator::Value(self.parse()?);
3159
3160                    end = match calc_value {
3161                        CalcValueOrOperator::Value(ref calc_value) => match calc_value {
3162                            CalcValue::Number(item) => item.span.hi,
3163                            CalcValue::Percentage(item) => item.span.hi,
3164                            CalcValue::Constant(item) => item.span.hi,
3165                            CalcValue::Sum(item) => item.span.hi,
3166                            CalcValue::Function(item) => item.span.hi,
3167                            CalcValue::Dimension(item) => match item {
3168                                Dimension::Length(item) => item.span.hi,
3169                                Dimension::Angle(item) => item.span.hi,
3170                                Dimension::Time(item) => item.span.hi,
3171                                Dimension::Frequency(item) => item.span.hi,
3172                                Dimension::Resolution(item) => item.span.hi,
3173                                Dimension::Flex(item) => item.span.hi,
3174                                Dimension::UnknownDimension(item) => item.span.hi,
3175                            },
3176                        },
3177                        _ => {
3178                            unreachable!();
3179                        }
3180                    };
3181
3182                    expressions.push(calc_value);
3183                }
3184                _ => {
3185                    break;
3186                }
3187            }
3188        }
3189
3190        Ok(CalcProduct {
3191            span: Span::new(start, end),
3192            expressions,
3193        })
3194    }
3195}
3196
3197impl<I> Parse<CalcOperator> for Parser<I>
3198where
3199    I: ParserInput,
3200{
3201    fn parse(&mut self) -> PResult<CalcOperator> {
3202        let span = self.input.cur_span();
3203
3204        match cur!(self) {
3205            tok!("+") => {
3206                bump!(self);
3207
3208                Ok(CalcOperator {
3209                    span: span!(self, span.lo),
3210                    value: CalcOperatorType::Add,
3211                })
3212            }
3213            tok!("-") => {
3214                bump!(self);
3215
3216                Ok(CalcOperator {
3217                    span: span!(self, span.lo),
3218                    value: CalcOperatorType::Sub,
3219                })
3220            }
3221            tok!("*") => {
3222                bump!(self);
3223
3224                Ok(CalcOperator {
3225                    span: span!(self, span.lo),
3226                    value: CalcOperatorType::Mul,
3227                })
3228            }
3229            tok!("/") => {
3230                bump!(self);
3231
3232                Ok(CalcOperator {
3233                    span: span!(self, span.lo),
3234                    value: CalcOperatorType::Div,
3235                })
3236            }
3237            _ => {
3238                let span = self.input.cur_span();
3239
3240                return Err(Error::new(
3241                    span,
3242                    ErrorKind::Expected("'+', '-', '*' or '/' delim tokens"),
3243                ));
3244            }
3245        }
3246    }
3247}
3248
3249impl<I> Parse<CalcValue> for Parser<I>
3250where
3251    I: ParserInput,
3252{
3253    fn parse(&mut self) -> PResult<CalcValue> {
3254        match cur!(self) {
3255            tok!("number") => Ok(CalcValue::Number(self.parse()?)),
3256            tok!("dimension") => Ok(CalcValue::Dimension(self.parse()?)),
3257            tok!("percentage") => Ok(CalcValue::Percentage(self.parse()?)),
3258            Token::Ident { value, .. } => {
3259                match &*value.to_ascii_lowercase() {
3260                    "e" | "pi" | "infinity" | "-infinity" | "nan" => {}
3261                    _ => {
3262                        let span = self.input.cur_span();
3263
3264                        return Err(Error::new(
3265                            span,
3266                            ErrorKind::Expected(
3267                                "'e', 'pi', 'infinity', '-infinity' or 'NaN', ident tokens",
3268                            ),
3269                        ));
3270                    }
3271                }
3272
3273                Ok(CalcValue::Constant(self.parse()?))
3274            }
3275            tok!("(") => {
3276                let span = self.input.cur_span();
3277
3278                expect!(self, "(");
3279
3280                self.input.skip_ws();
3281
3282                let mut calc_sum_in_parens: CalcSum = self.parse()?;
3283
3284                self.input.skip_ws();
3285
3286                expect!(self, ")");
3287
3288                calc_sum_in_parens.span = span!(self, span.lo);
3289
3290                Ok(CalcValue::Sum(calc_sum_in_parens))
3291            }
3292            tok!("function") => Ok(CalcValue::Function(self.parse()?)),
3293            _ => {
3294                let span = self.input.cur_span();
3295
3296                return Err(Error::new(
3297                    span,
3298                    ErrorKind::Expected(
3299                        "'number', 'dimension', 'percentage', 'ident', '(' or 'function' tokens",
3300                    ),
3301                ));
3302            }
3303        }
3304    }
3305}
3306
3307impl<I> Parse<FamilyName> for Parser<I>
3308where
3309    I: ParserInput,
3310{
3311    fn parse(&mut self) -> PResult<FamilyName> {
3312        match cur!(self) {
3313            tok!("string") => Ok(FamilyName::Str(self.parse()?)),
3314            tok!("ident") => {
3315                let span = self.input.cur_span();
3316
3317                let mut value = vec![self.parse()?];
3318
3319                loop {
3320                    self.input.skip_ws();
3321
3322                    if !is!(self, "ident") {
3323                        break;
3324                    }
3325
3326                    value.push(self.parse()?);
3327                }
3328
3329                Ok(FamilyName::SequenceOfCustomIdents(SequenceOfCustomIdents {
3330                    span: span!(self, span.lo),
3331                    value,
3332                }))
3333            }
3334            _ => {
3335                let span = self.input.cur_span();
3336
3337                return Err(Error::new(
3338                    span,
3339                    ErrorKind::Expected("'string' or 'ident' tokens"),
3340                ));
3341            }
3342        }
3343    }
3344}
3345
3346pub(crate) fn is_math_function(name: &Atom) -> bool {
3347    matches_eq_ignore_ascii_case!(
3348        name,
3349        "calc",
3350        "-moz-calc",
3351        "-webkit-calc",
3352        "sin",
3353        "cos",
3354        "tan",
3355        "asin",
3356        "acos",
3357        "atan",
3358        "sqrt",
3359        "exp",
3360        "abs",
3361        "sign",
3362        "min",
3363        "max",
3364        "hypot",
3365        "clamp",
3366        "round",
3367        "mod",
3368        "rem",
3369        "atan2",
3370        "pow",
3371        "log"
3372    )
3373}
3374
3375fn is_absolute_color_base_function(name: &Atom) -> bool {
3376    matches_eq_ignore_ascii_case!(
3377        name,
3378        "rgb",
3379        "rgba",
3380        "hsl",
3381        "hsla",
3382        "hwb",
3383        "lab",
3384        "lch",
3385        "oklab",
3386        "oklch",
3387        "color",
3388        "color-mix",
3389        "color-contrast"
3390    )
3391}
3392
3393fn is_system_color(name: &Atom) -> bool {
3394    matches_eq_ignore_ascii_case!(
3395        name,
3396        "canvas",
3397        "canvastext",
3398        "linktext",
3399        "visitedtext",
3400        "activetext",
3401        "buttonface",
3402        "buttontext",
3403        "buttonborder",
3404        "field",
3405        "fieldtext",
3406        "highlight",
3407        "highlighttext",
3408        "selecteditem",
3409        "selecteditemtext",
3410        "mark",
3411        "marktext",
3412        "graytext",
3413        // Deprecated
3414        "activeborder",
3415        "activecaption",
3416        "appWorkspace",
3417        "background",
3418        "buttonhighlight",
3419        "buttonshadow",
3420        "captiontext",
3421        "inactiveborder",
3422        "inactivecaption",
3423        "inactivecaptiontext",
3424        "infobackground",
3425        "infotext",
3426        "menu",
3427        "menutext",
3428        "scrollbar",
3429        "threeddarkshadow",
3430        "threedface",
3431        "threedhighlight",
3432        "threedlightshadow",
3433        "threedshadow",
3434        "window",
3435        "windowframe",
3436        "windowtext",
3437        // Mozilla System Color Extensions
3438        "-moz-buttondefault",
3439        "-moz-buttonhoverface",
3440        "-moz-buttonhovertext",
3441        "-moz-cellhighlight",
3442        "-moz-cellhighlighttext",
3443        "-moz-combobox",
3444        "-moz-comboboxtext",
3445        "-moz-dialog",
3446        "-moz-dialogtext",
3447        "-moz-dragtargetzone",
3448        "-moz-eventreerow",
3449        "-moz-html-cellhighlight",
3450        "-moz-html-cellhighlighttext",
3451        "-moz-mac-accentdarkestshadow",
3452        "-moz-mac-accentdarkshadow",
3453        "-moz-mac-accentface",
3454        "-moz-mac-accentlightesthighlight",
3455        "-moz-mac-accentlightshadow",
3456        "-moz-mac-accentregularhighlight",
3457        "-moz-mac-accentregularshadow",
3458        "-moz-mac-chrome-active",
3459        "-moz-mac-chrome-inactive",
3460        "-moz-mac-focusring",
3461        "-moz-mac-menuselect",
3462        "-moz-mac-menushadow",
3463        "-moz-mac-menutextselect",
3464        "-moz-menuhover",
3465        "-moz-menuhovertext",
3466        "-moz-menubartext",
3467        "-moz-menubarhovertext",
3468        "-moz-nativehyperlinktext",
3469        "-moz-oddtreerow",
3470        "-moz-win-communicationstext",
3471        "-moz-win-mediatext",
3472        "-moz-win-accentcolor",
3473        "-moz-win-accentcolortext",
3474        // Mozilla Color Preference Extensions
3475        "-moz-activehyperlinktext",
3476        "-moz-default-background-color",
3477        "-moz-default-color",
3478        "-moz-hyperlinktext",
3479        "-moz-visitedhyperlinktext"
3480    )
3481}
3482
3483fn is_named_color(name: &Atom) -> bool {
3484    matches_eq_ignore_ascii_case!(
3485        name,
3486        "aliceblue",
3487        "antiquewhite",
3488        "aqua",
3489        "aquamarine",
3490        "azure",
3491        "beige",
3492        "bisque",
3493        "black",
3494        "blanchedalmond",
3495        "blue",
3496        "blueviolet",
3497        "brown",
3498        "burlywood",
3499        "cadetblue",
3500        "chartreuse",
3501        "chocolate",
3502        "coral",
3503        "cornflowerblue",
3504        "cornsilk",
3505        "crimson",
3506        "cyan",
3507        "darkblue",
3508        "darkcyan",
3509        "darkgoldenrod",
3510        "darkgray",
3511        "darkgreen",
3512        "darkgrey",
3513        "darkkhaki",
3514        "darkmagenta",
3515        "darkolivegreen",
3516        "darkorange",
3517        "darkorchid",
3518        "darkred",
3519        "darksalmon",
3520        "darkseagreen",
3521        "darkslateblue",
3522        "darkslategray",
3523        "darkslategrey",
3524        "darkturquoise",
3525        "darkviolet",
3526        "deeppink",
3527        "deepskyblue",
3528        "dimgray",
3529        "dimgrey",
3530        "dodgerblue",
3531        "firebrick",
3532        "floralwhite",
3533        "forestgreen",
3534        "fuchsia",
3535        "gainsboro",
3536        "ghostwhite",
3537        "gold",
3538        "goldenrod",
3539        "gray",
3540        "green",
3541        "greenyellow",
3542        "grey",
3543        "honeydew",
3544        "hotpink",
3545        "indianred",
3546        "indigo",
3547        "ivory",
3548        "khaki",
3549        "lavender",
3550        "lavenderblush",
3551        "lawngreen",
3552        "lemonchiffon",
3553        "lightblue",
3554        "lightcoral",
3555        "lightcyan",
3556        "lightgoldenrodyellow",
3557        "lightgray",
3558        "lightgreen",
3559        "lightgrey",
3560        "lightpink",
3561        "lightsalmon",
3562        "lightseagreen",
3563        "lightskyblue",
3564        "lightslategray",
3565        "lightslategrey",
3566        "lightsteelblue",
3567        "lightyellow",
3568        "lime",
3569        "limegreen",
3570        "linen",
3571        "magenta",
3572        "maroon",
3573        "mediumaquamarine",
3574        "mediumblue",
3575        "mediumorchid",
3576        "mediumpurple",
3577        "mediumseagreen",
3578        "mediumslateblue",
3579        "mediumspringgreen",
3580        "mediumturquoise",
3581        "mediumvioletred",
3582        "midnightblue",
3583        "mintcream",
3584        "mistyrose",
3585        "moccasin",
3586        "navajowhite",
3587        "navy",
3588        "oldlace",
3589        "olive",
3590        "olivedrab",
3591        "orange",
3592        "orangered",
3593        "orchid",
3594        "palegoldenrod",
3595        "palegreen",
3596        "paleturquoise",
3597        "palevioletred",
3598        "papayawhip",
3599        "peachpuff",
3600        "peru",
3601        "pink",
3602        "plum",
3603        "powderblue",
3604        "purple",
3605        "rebeccapurple",
3606        "red",
3607        "rosybrown",
3608        "royalblue",
3609        "saddlebrown",
3610        "salmon",
3611        "sandybrown",
3612        "seagreen",
3613        "seashell",
3614        "sienna",
3615        "silver",
3616        "skyblue",
3617        "slateblue",
3618        "slategray",
3619        "slategrey",
3620        "snow",
3621        "springgreen",
3622        "steelblue",
3623        "tan",
3624        "teal",
3625        "thistle",
3626        "tomato",
3627        "turquoise",
3628        "violet",
3629        "wheat",
3630        "white",
3631        "whitesmoke",
3632        "yellow",
3633        "yellowgreen"
3634    )
3635}
3636
3637fn is_length_unit(unit: &Atom) -> bool {
3638    matches_eq_ignore_ascii_case!(
3639        unit, "em", "rem", "ex", "rex", "cap", "rcap", "ch", "rch", "ic", "ric", "lh", "rlh",
3640        //  Viewport-percentage Lengths
3641        "vw", "svw", "lvw", "dvw", "vh", "svh", "lvh", "dvh", "vi", "svi", "lvi", "dvi", "vb",
3642        "svb", "lvb", "dvb", "vmin", "svmin", "lvmin", "dvmin", "vmax", "svmax", "lvmax", "dvmax",
3643        // Absolute lengths
3644        "cm", "mm", "q", "in", "pc", "pt", "px", "mozmm"
3645    )
3646}
3647
3648fn is_container_lengths_unit(unit: &Atom) -> bool {
3649    matches_eq_ignore_ascii_case!(unit, "cqw", "cqh", "cqi", "cqb", "cqmin", "cqmax")
3650}
3651
3652fn is_angle_unit(unit: &Atom) -> bool {
3653    matches_eq_ignore_ascii_case!(unit, "deg", "grad", "rad", "turn")
3654}
3655
3656fn is_time_unit(unit: &Atom) -> bool {
3657    matches_eq_ignore_ascii_case!(unit, "s", "ms")
3658}
3659
3660fn is_frequency_unit(unit: &Atom) -> bool {
3661    matches_eq_ignore_ascii_case!(unit, "hz", "khz")
3662}
3663
3664fn is_resolution_unit(unit: &Atom) -> bool {
3665    matches_eq_ignore_ascii_case!(unit, "dpi", "dpcm", "dppx", "x")
3666}
3667
3668fn is_flex_unit(unit: &Atom) -> bool {
3669    matches_eq_ignore_ascii_case!(unit, "fr")
3670}