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(dimension_token) => {
1968                match &dimension_token.unit {
1969                    // <length>
1970                    unit if is_length_unit(unit)
1971                        || (self.ctx.in_container_at_rule && is_container_lengths_unit(unit)) =>
1972                    {
1973                        Ok(Dimension::Length(self.parse()?))
1974                    }
1975                    // <angle>
1976                    unit if is_angle_unit(unit) => Ok(Dimension::Angle(self.parse()?)),
1977                    // <time>
1978                    unit if is_time_unit(unit) => Ok(Dimension::Time(self.parse()?)),
1979                    // <frequency>
1980                    unit if is_frequency_unit(unit) => Ok(Dimension::Frequency(self.parse()?)),
1981                    // <resolution>
1982                    unit if is_resolution_unit(unit) => Ok(Dimension::Resolution(self.parse()?)),
1983                    // <flex>
1984                    unit if is_flex_unit(unit) => Ok(Dimension::Flex(self.parse()?)),
1985                    _ => Ok(Dimension::UnknownDimension(self.parse()?)),
1986                }
1987            }
1988            _ => {
1989                unreachable!()
1990            }
1991        }
1992    }
1993}
1994
1995impl<I> Parse<Length> for Parser<I>
1996where
1997    I: ParserInput,
1998{
1999    fn parse(&mut self) -> PResult<Length> {
2000        let span = self.input.cur_span();
2001
2002        if !is!(self, Dimension) {
2003            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2004        }
2005
2006        match bump!(self) {
2007            Token::Dimension(dimension_token) => {
2008                let DimensionToken {
2009                    value,
2010                    unit,
2011                    raw_value,
2012                    raw_unit,
2013                    ..
2014                } = *dimension_token;
2015
2016                // TODO validate
2017
2018                let unit_len = raw_unit.len() as u32;
2019
2020                Ok(Length {
2021                    span,
2022                    value: Number {
2023                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2024                        value,
2025                        raw: Some(raw_value),
2026                    },
2027                    unit: Ident {
2028                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2029                        value: unit,
2030                        raw: Some(raw_unit),
2031                    },
2032                })
2033            }
2034            _ => {
2035                unreachable!()
2036            }
2037        }
2038    }
2039}
2040
2041impl<I> Parse<Angle> for Parser<I>
2042where
2043    I: ParserInput,
2044{
2045    fn parse(&mut self) -> PResult<Angle> {
2046        let span = self.input.cur_span();
2047
2048        if !is!(self, Dimension) {
2049            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2050        }
2051
2052        match bump!(self) {
2053            Token::Dimension(dimension_token) => {
2054                let DimensionToken {
2055                    value,
2056                    unit,
2057                    raw_value,
2058                    raw_unit,
2059                    ..
2060                } = *dimension_token;
2061
2062                if !is_angle_unit(&unit) {
2063                    return Err(Error::new(
2064                        span,
2065                        ErrorKind::Expected("'deg', 'grad', 'rad' or 'turn' units"),
2066                    ));
2067                }
2068
2069                let unit_len = raw_unit.len() as u32;
2070
2071                Ok(Angle {
2072                    span,
2073                    value: Number {
2074                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2075                        value,
2076                        raw: Some(raw_value),
2077                    },
2078                    unit: Ident {
2079                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2080                        value: unit,
2081                        raw: Some(raw_unit),
2082                    },
2083                })
2084            }
2085            _ => {
2086                unreachable!()
2087            }
2088        }
2089    }
2090}
2091
2092impl<I> Parse<Time> for Parser<I>
2093where
2094    I: ParserInput,
2095{
2096    fn parse(&mut self) -> PResult<Time> {
2097        let span = self.input.cur_span();
2098
2099        if !is!(self, Dimension) {
2100            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2101        }
2102
2103        match bump!(self) {
2104            Token::Dimension(dimension_token) => {
2105                let DimensionToken {
2106                    value,
2107                    unit,
2108                    raw_value,
2109                    raw_unit,
2110                    ..
2111                } = *dimension_token;
2112
2113                if !is_time_unit(&unit) {
2114                    return Err(Error::new(span, ErrorKind::Expected("'s' or 'ms' units")));
2115                }
2116
2117                let unit_len = raw_unit.len() as u32;
2118
2119                Ok(Time {
2120                    span,
2121                    value: Number {
2122                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2123                        value,
2124                        raw: Some(raw_value),
2125                    },
2126                    unit: Ident {
2127                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2128                        value: unit,
2129                        raw: Some(raw_unit),
2130                    },
2131                })
2132            }
2133            _ => {
2134                unreachable!()
2135            }
2136        }
2137    }
2138}
2139
2140impl<I> Parse<Frequency> for Parser<I>
2141where
2142    I: ParserInput,
2143{
2144    fn parse(&mut self) -> PResult<Frequency> {
2145        let span = self.input.cur_span();
2146
2147        if !is!(self, Dimension) {
2148            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2149        }
2150
2151        match bump!(self) {
2152            Token::Dimension(dimension_token) => {
2153                let DimensionToken {
2154                    value,
2155                    unit,
2156                    raw_value,
2157                    raw_unit,
2158                    ..
2159                } = *dimension_token;
2160
2161                if !is_frequency_unit(&unit) {
2162                    return Err(Error::new(span, ErrorKind::Expected("'Hz' or 'kHz' units")));
2163                }
2164
2165                let unit_len = raw_unit.len() as u32;
2166
2167                Ok(Frequency {
2168                    span,
2169                    value: Number {
2170                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2171                        value,
2172                        raw: Some(raw_value),
2173                    },
2174                    unit: Ident {
2175                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2176                        value: unit,
2177                        raw: Some(raw_unit),
2178                    },
2179                })
2180            }
2181            _ => {
2182                unreachable!()
2183            }
2184        }
2185    }
2186}
2187
2188impl<I> Parse<Resolution> for Parser<I>
2189where
2190    I: ParserInput,
2191{
2192    fn parse(&mut self) -> PResult<Resolution> {
2193        let span = self.input.cur_span();
2194
2195        if !is!(self, Dimension) {
2196            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2197        }
2198
2199        match bump!(self) {
2200            Token::Dimension(dimension_token) => {
2201                let DimensionToken {
2202                    value,
2203                    unit,
2204                    raw_value,
2205                    raw_unit,
2206                    ..
2207                } = *dimension_token;
2208
2209                if !is_resolution_unit(&unit) {
2210                    return Err(Error::new(
2211                        span,
2212                        ErrorKind::Expected("'dpi', 'dpcm', 'dppx' or 'x' units"),
2213                    ));
2214                }
2215
2216                let unit_len = raw_unit.len() as u32;
2217
2218                Ok(Resolution {
2219                    span,
2220                    value: Number {
2221                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2222                        value,
2223                        raw: Some(raw_value),
2224                    },
2225                    unit: Ident {
2226                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2227                        value: unit,
2228                        raw: Some(raw_unit),
2229                    },
2230                })
2231            }
2232            _ => {
2233                unreachable!()
2234            }
2235        }
2236    }
2237}
2238
2239impl<I> Parse<Flex> for Parser<I>
2240where
2241    I: ParserInput,
2242{
2243    fn parse(&mut self) -> PResult<Flex> {
2244        let span = self.input.cur_span();
2245
2246        if !is!(self, Dimension) {
2247            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2248        }
2249
2250        match bump!(self) {
2251            Token::Dimension(dimension_token) => {
2252                let DimensionToken {
2253                    value,
2254                    unit,
2255                    raw_value,
2256                    raw_unit,
2257                    ..
2258                } = *dimension_token;
2259
2260                if !is_flex_unit(&unit) {
2261                    return Err(Error::new(span, ErrorKind::Expected("'fr' unit")));
2262                }
2263
2264                let unit_len = raw_unit.len() as u32;
2265
2266                Ok(Flex {
2267                    span,
2268                    value: Number {
2269                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2270                        value,
2271                        raw: Some(raw_value),
2272                    },
2273                    unit: Ident {
2274                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2275                        value: unit,
2276                        raw: Some(raw_unit),
2277                    },
2278                })
2279            }
2280            _ => {
2281                unreachable!()
2282            }
2283        }
2284    }
2285}
2286
2287impl<I> Parse<UnknownDimension> for Parser<I>
2288where
2289    I: ParserInput,
2290{
2291    fn parse(&mut self) -> PResult<UnknownDimension> {
2292        let span = self.input.cur_span();
2293
2294        if !is!(self, Dimension) {
2295            return Err(Error::new(span, ErrorKind::Expected("dimension token")));
2296        }
2297
2298        match bump!(self) {
2299            Token::Dimension(dimension_token) => {
2300                let DimensionToken {
2301                    value,
2302                    unit,
2303                    raw_value,
2304                    raw_unit,
2305                    ..
2306                } = *dimension_token;
2307
2308                let unit_len = raw_unit.len() as u32;
2309
2310                Ok(UnknownDimension {
2311                    span,
2312                    value: Number {
2313                        span: Span::new(span.lo, span.hi - BytePos(unit_len)),
2314                        value,
2315                        raw: Some(raw_value),
2316                    },
2317                    unit: Ident {
2318                        span: Span::new(span.hi - BytePos(unit_len), span.hi),
2319                        value: self.input.atom(unit.to_lowercase()),
2320                        raw: Some(raw_unit),
2321                    },
2322                })
2323            }
2324            _ => {
2325                unreachable!()
2326            }
2327        }
2328    }
2329}
2330
2331impl<I> Parse<Color> for Parser<I>
2332where
2333    I: ParserInput,
2334{
2335    fn parse(&mut self) -> PResult<Color> {
2336        let span = self.input.cur_span();
2337
2338        match cur!(self) {
2339            // currentcolor | <system-color>
2340            Token::Ident { value, .. }
2341                if value.as_ref().eq_ignore_ascii_case("currentcolor")
2342                    || is_system_color(value) =>
2343            {
2344                Ok(Color::CurrentColorOrSystemColor(self.parse()?))
2345            }
2346            // <device-cmyk()>
2347            Token::Function { value, .. } if value.as_ref().eq_ignore_ascii_case("device-cmyk") => {
2348                Ok(Color::Function(self.parse()?))
2349            }
2350            // <absolute-color-base>
2351            _ => match self.parse() {
2352                Ok(absolute_color_base) => Ok(Color::AbsoluteColorBase(absolute_color_base)),
2353                Err(_) => {
2354                    return Err(Error::new(
2355                        span,
2356                        ErrorKind::Expected(
2357                            "hash, ident (with named color, system color, 'transparent' or \
2358                             'currentColor' value) or function (with color function name) token",
2359                        ),
2360                    ));
2361                }
2362            },
2363        }
2364    }
2365}
2366
2367impl<I> Parse<AbsoluteColorBase> for Parser<I>
2368where
2369    I: ParserInput,
2370{
2371    fn parse(&mut self) -> PResult<AbsoluteColorBase> {
2372        let span = self.input.cur_span();
2373
2374        match cur!(self) {
2375            tok!("#") => Ok(AbsoluteColorBase::HexColor(self.parse()?)),
2376            Token::Ident { value, .. } => {
2377                if !(is_named_color(value) || value.as_ref().eq_ignore_ascii_case("transparent")) {
2378                    let span = self.input.cur_span();
2379
2380                    return Err(Error::new(
2381                        span,
2382                        ErrorKind::Expected("known named color or 'transparent' keyword"),
2383                    ));
2384                }
2385
2386                Ok(AbsoluteColorBase::NamedColorOrTransparent(self.parse()?))
2387            }
2388            Token::Function { value, .. } if is_absolute_color_base_function(value) => {
2389                Ok(AbsoluteColorBase::Function(self.parse()?))
2390            }
2391            _ => {
2392                return Err(Error::new(
2393                    span,
2394                    ErrorKind::Expected(
2395                        "hash, ident (with named color or 'transparent' value) or function (with \
2396                         color function name) token",
2397                    ),
2398                ));
2399            }
2400        }
2401    }
2402}
2403
2404impl<I> Parse<HexColor> for Parser<I>
2405where
2406    I: ParserInput,
2407{
2408    fn parse(&mut self) -> PResult<HexColor> {
2409        let span = self.input.cur_span();
2410
2411        if !is!(self, "#") {
2412            return Err(Error::new(span, ErrorKind::Expected("hash token")));
2413        }
2414
2415        match bump!(self) {
2416            Token::Hash { value, raw, .. } => {
2417                if value.chars().any(|x| !x.is_ascii_hexdigit()) {
2418                    return Err(Error::new(
2419                        span,
2420                        ErrorKind::Unexpected("character in hex color"),
2421                    ));
2422                }
2423
2424                Ok(HexColor {
2425                    span,
2426                    value,
2427                    raw: Some(raw),
2428                })
2429            }
2430            _ => {
2431                unreachable!()
2432            }
2433        }
2434    }
2435}
2436
2437impl<I> Parse<AlphaValue> for Parser<I>
2438where
2439    I: ParserInput,
2440{
2441    fn parse(&mut self) -> PResult<AlphaValue> {
2442        if !is_one_of!(self, "percentage", "number") {
2443            let span = self.input.cur_span();
2444
2445            return Err(Error::new(
2446                span,
2447                ErrorKind::Expected("percentage or number token"),
2448            ));
2449        }
2450
2451        match cur!(self) {
2452            tok!("percentage") => Ok(AlphaValue::Percentage(self.parse()?)),
2453            tok!("number") => Ok(AlphaValue::Number(self.parse()?)),
2454            _ => {
2455                unreachable!()
2456            }
2457        }
2458    }
2459}
2460
2461impl<I> Parse<Hue> for Parser<I>
2462where
2463    I: ParserInput,
2464{
2465    fn parse(&mut self) -> PResult<Hue> {
2466        if !is_one_of!(self, "number", "dimension") {
2467            let span = self.input.cur_span();
2468
2469            return Err(Error::new(
2470                span,
2471                ErrorKind::Expected("number or dimension token"),
2472            ));
2473        }
2474
2475        match cur!(self) {
2476            tok!("number") => Ok(Hue::Number(self.parse()?)),
2477            tok!("dimension") => Ok(Hue::Angle(self.parse()?)),
2478            _ => {
2479                unreachable!()
2480            }
2481        }
2482    }
2483}
2484
2485impl<I> Parse<CmykComponent> for Parser<I>
2486where
2487    I: ParserInput,
2488{
2489    fn parse(&mut self) -> PResult<CmykComponent> {
2490        if !is_one_of!(self, "number", "percentage", "function") {
2491            let span = self.input.cur_span();
2492
2493            return Err(Error::new(
2494                span,
2495                ErrorKind::Expected("number, function or percentage token"),
2496            ));
2497        }
2498
2499        match cur!(self) {
2500            tok!("number") => Ok(CmykComponent::Number(self.parse()?)),
2501            tok!("percentage") => Ok(CmykComponent::Percentage(self.parse()?)),
2502            Token::Function { value, .. } => {
2503                if !is_math_function(value) {
2504                    let span = self.input.cur_span();
2505
2506                    return Err(Error::new(span, ErrorKind::Expected("math function token")));
2507                }
2508
2509                Ok(CmykComponent::Function(self.parse()?))
2510            }
2511            _ => {
2512                unreachable!()
2513            }
2514        }
2515    }
2516}
2517
2518impl<I> Parse<Percentage> for Parser<I>
2519where
2520    I: ParserInput,
2521{
2522    fn parse(&mut self) -> PResult<Percentage> {
2523        let span = self.input.cur_span();
2524
2525        if !is!(self, Percentage) {
2526            return Err(Error::new(span, ErrorKind::Expected("percentage token")));
2527        }
2528
2529        match bump!(self) {
2530            Token::Percentage { value, raw } => {
2531                let value = Number {
2532                    span: Span::new(span.lo, span.hi - BytePos(1)),
2533                    value,
2534                    raw: Some(raw),
2535                };
2536
2537                Ok(Percentage { span, value })
2538            }
2539            _ => {
2540                unreachable!()
2541            }
2542        }
2543    }
2544}
2545
2546impl<I> Parse<Str> for Parser<I>
2547where
2548    I: ParserInput,
2549{
2550    fn parse(&mut self) -> PResult<Str> {
2551        let span = self.input.cur_span();
2552
2553        if !is!(self, "string") {
2554            return Err(Error::new(span, ErrorKind::Expected("string token")));
2555        }
2556
2557        match bump!(self) {
2558            Token::String { value, raw } => Ok(Str {
2559                span,
2560                value,
2561                raw: Some(raw),
2562            }),
2563            _ => {
2564                unreachable!()
2565            }
2566        }
2567    }
2568}
2569
2570impl<I> Parse<Url> for Parser<I>
2571where
2572    I: ParserInput,
2573{
2574    fn parse(&mut self) -> PResult<Url> {
2575        let span = self.input.cur_span();
2576
2577        if !is_one_of!(self, Url, Function) {
2578            return Err(Error::new(
2579                span,
2580                ErrorKind::Expected("url or function (with 'url' or 'src' name) token"),
2581            ));
2582        }
2583
2584        match bump!(self) {
2585            Token::Url { value, raw } => {
2586                let name_length = raw.0.len() as u32;
2587                let name = Ident {
2588                    span: Span::new(span.lo, span.lo + BytePos(name_length)),
2589                    value: self.input.atom("url"),
2590                    raw: Some(raw.0),
2591                };
2592                let value = Some(Box::new(UrlValue::Raw(UrlValueRaw {
2593                    span: Span::new(span.lo + BytePos(name_length + 1), span.hi - BytePos(1)),
2594                    value,
2595                    raw: Some(raw.1),
2596                })));
2597
2598                Ok(Url {
2599                    span: span!(self, span.lo),
2600                    name,
2601                    value,
2602                    modifiers: None,
2603                })
2604            }
2605            Token::Function {
2606                value: function_name,
2607                raw: raw_function_name,
2608            } => {
2609                if !matches_eq_ignore_ascii_case!(function_name, "url", "src") {
2610                    return Err(Error::new(
2611                        span,
2612                        ErrorKind::Expected("'url' or 'src' name of a function token"),
2613                    ));
2614                }
2615
2616                let name = Ident {
2617                    span: Span::new(span.lo, span.hi - BytePos(1)),
2618                    value: function_name,
2619                    raw: Some(raw_function_name),
2620                };
2621
2622                self.input.skip_ws();
2623
2624                let value = match cur!(self) {
2625                    tok!("string") => Some(Box::new(UrlValue::Str(self.parse()?))),
2626                    _ => None,
2627                };
2628
2629                self.input.skip_ws();
2630
2631                let mut modifiers = Vec::new();
2632
2633                loop {
2634                    if is!(self, ")") {
2635                        break;
2636                    }
2637
2638                    match cur!(self) {
2639                        tok!("ident") => {
2640                            modifiers.push(UrlModifier::Ident(self.parse()?));
2641                        }
2642                        tok!("function") => {
2643                            modifiers.push(UrlModifier::Function(self.parse()?));
2644                        }
2645                        _ => {
2646                            let span = self.input.cur_span();
2647
2648                            return Err(Error::new(span, ErrorKind::Expected("ident or function")));
2649                        }
2650                    }
2651
2652                    self.input.skip_ws();
2653                }
2654
2655                expect!(self, ")");
2656
2657                Ok(Url {
2658                    span: span!(self, span.lo),
2659                    name,
2660                    value,
2661                    modifiers: Some(modifiers),
2662                })
2663            }
2664            _ => {
2665                unreachable!()
2666            }
2667        }
2668    }
2669}
2670
2671// <urange> =
2672//   u '+' <ident-token> '?'* |
2673//   u <dimension-token> '?'* |
2674//   u <number-token> '?'* |
2675//   u <number-token> <dimension-token> |
2676//   u <number-token> <number-token> |
2677//   u '+' '?'+
2678impl<I> Parse<UnicodeRange> for Parser<I>
2679where
2680    I: ParserInput,
2681{
2682    fn parse(&mut self) -> PResult<UnicodeRange> {
2683        let span = self.input.cur_span();
2684        let mut unicode_range = String::new();
2685
2686        // should start with `u` or `U`
2687        match cur!(self) {
2688            Token::Ident { value, .. } if matches_eq_ignore_ascii_case!(value, "u") => {
2689                let u = match bump!(self) {
2690                    Token::Ident { value, .. } => value,
2691                    _ => {
2692                        unreachable!();
2693                    }
2694                };
2695
2696                unicode_range.push_str(&u);
2697            }
2698            _ => {
2699                return Err(Error::new(span, ErrorKind::Expected("'u' ident token")));
2700            }
2701        };
2702
2703        match cur!(self) {
2704            // u '+' <ident-token> '?'*
2705            // u '+' '?'+
2706            Token::Delim { value } if *value == '+' => {
2707                let plus = match bump!(self) {
2708                    Token::Delim { value } => value,
2709                    _ => {
2710                        unreachable!();
2711                    }
2712                };
2713
2714                unicode_range.push(plus);
2715
2716                if is!(self, Ident) {
2717                    let ident = match bump!(self) {
2718                        Token::Ident { value, .. } => value,
2719                        _ => {
2720                            unreachable!();
2721                        }
2722                    };
2723
2724                    unicode_range.push_str(&ident);
2725
2726                    loop {
2727                        if !is!(self, "?") {
2728                            break;
2729                        }
2730
2731                        let question = match bump!(self) {
2732                            Token::Delim { value } => value,
2733                            _ => {
2734                                unreachable!();
2735                            }
2736                        };
2737
2738                        unicode_range.push(question);
2739                    }
2740                } else {
2741                    let question = match bump!(self) {
2742                        Token::Delim { value } if value == '?' => value,
2743                        _ => {
2744                            return Err(Error::new(span, ErrorKind::Expected("'?' delim token")));
2745                        }
2746                    };
2747
2748                    unicode_range.push(question);
2749
2750                    loop {
2751                        if !is!(self, "?") {
2752                            break;
2753                        }
2754
2755                        let question = match bump!(self) {
2756                            Token::Delim { value } => value,
2757                            _ => {
2758                                unreachable!();
2759                            }
2760                        };
2761
2762                        unicode_range.push(question);
2763                    }
2764                }
2765            }
2766            // u <number-token> '?'*
2767            // u <number-token> <dimension-token>
2768            // u <number-token> <number-token>
2769            tok!("number") => {
2770                let number = match bump!(self) {
2771                    Token::Number { raw, .. } => raw,
2772                    _ => {
2773                        unreachable!();
2774                    }
2775                };
2776
2777                unicode_range.push_str(&number);
2778
2779                if !is!(self, EOF) {
2780                    match cur!(self) {
2781                        tok!("?") => {
2782                            let question = match bump!(self) {
2783                                Token::Delim { value } => value,
2784                                _ => {
2785                                    unreachable!();
2786                                }
2787                            };
2788
2789                            unicode_range.push(question);
2790
2791                            loop {
2792                                if !is!(self, "?") {
2793                                    break;
2794                                }
2795
2796                                let question = match bump!(self) {
2797                                    Token::Delim { value } => value,
2798                                    _ => {
2799                                        unreachable!();
2800                                    }
2801                                };
2802
2803                                unicode_range.push(question);
2804                            }
2805                        }
2806                        tok!("dimension") => {
2807                            let raw = match bump!(self) {
2808                                Token::Dimension(dimension_token) => {
2809                                    (dimension_token.raw_value, dimension_token.raw_unit)
2810                                }
2811                                _ => {
2812                                    unreachable!();
2813                                }
2814                            };
2815
2816                            unicode_range.push_str(&raw.0);
2817                            unicode_range.push_str(&raw.1);
2818                        }
2819                        tok!("number") => {
2820                            let number = match bump!(self) {
2821                                Token::Number { raw, .. } => raw,
2822                                _ => {
2823                                    unreachable!();
2824                                }
2825                            };
2826
2827                            unicode_range.push_str(&number);
2828                        }
2829                        _ => {}
2830                    }
2831                }
2832            }
2833            // u <dimension-token> '?'*
2834            tok!("dimension") => {
2835                let raw = match bump!(self) {
2836                    Token::Dimension(dimension_token) => {
2837                        (dimension_token.raw_value, dimension_token.raw_unit)
2838                    }
2839                    _ => {
2840                        unreachable!();
2841                    }
2842                };
2843
2844                unicode_range.push_str(&raw.0);
2845                unicode_range.push_str(&raw.1);
2846
2847                loop {
2848                    if !is!(self, "?") {
2849                        break;
2850                    }
2851
2852                    let question = match bump!(self) {
2853                        Token::Delim { value } => value,
2854                        _ => {
2855                            unreachable!();
2856                        }
2857                    };
2858
2859                    unicode_range.push(question);
2860                }
2861            }
2862            _ => {
2863                return Err(Error::new(
2864                    span,
2865                    ErrorKind::Expected("dimension, number or '?' delim token"),
2866                ));
2867            }
2868        }
2869
2870        let mut chars = unicode_range.chars();
2871
2872        // 1. Skipping the first u token, concatenate the representations of all the
2873        // tokens in the production together. Let this be text.
2874        chars.next();
2875
2876        // 2. If the first character of text is U+002B PLUS SIGN, consume it. Otherwise,
2877        // this is an invalid <urange>, and this algorithm must exit.
2878        let mut next = chars.next();
2879
2880        if next != Some('+') {
2881            return Err(Error::new(
2882                span,
2883                ErrorKind::Expected("'+' character after 'u' in unicode range"),
2884            ));
2885        } else {
2886            next = chars.next();
2887        }
2888
2889        // 3. Consume as many hex digits from text as possible. then consume as many
2890        // U+003F QUESTION MARK (?) code points as possible. If zero code points
2891        // were consumed, or more than six code points were consumed, this is an
2892        // invalid <urange>, and this algorithm must exit.
2893        let mut start = String::new();
2894
2895        loop {
2896            match next {
2897                Some(c) if c.is_ascii_digit() => {
2898                    start.push(c);
2899
2900                    next = chars.next();
2901                }
2902                Some(c @ 'A'..='F') | Some(c @ 'a'..='f') => {
2903                    start.push(c);
2904
2905                    next = chars.next();
2906                }
2907                _ => {
2908                    break;
2909                }
2910            }
2911        }
2912
2913        let mut has_question_mark = false;
2914
2915        while let Some(c @ '?') = next {
2916            has_question_mark = true;
2917
2918            start.push(c);
2919
2920            next = chars.next();
2921        }
2922
2923        let len = start.len();
2924
2925        if len == 0 || len > 6 {
2926            return Err(Error::new(
2927                span,
2928                ErrorKind::Expected(
2929                    "valid length (minimum 1 or maximum 6 hex digits) in the start of unicode \
2930                     range",
2931                ),
2932            ));
2933        }
2934
2935        // If any U+003F QUESTION MARK (?) code points were consumed, then:
2936        if has_question_mark {
2937            // 1. If there are any code points left in text, this is an invalid <urange>,
2938            // and this algorithm must exit.
2939            if next.is_some() {
2940                return Err(Error::new(
2941                    span,
2942                    ErrorKind::Expected("no characters after '?' in unicode range"),
2943                ));
2944            }
2945
2946            // 2. Interpret the consumed code points
2947            // as a hexadecimal number, with the U+003F QUESTION MARK (?) code points
2948            // replaced by U+0030 DIGIT ZERO (0) code points. This is the start value.
2949            //
2950            // 3. Interpret the consumed code points as a hexadecimal number again, with the
2951            // U+003F QUESTION MARK (?) code points replaced by U+0046 LATIN CAPITAL LETTER
2952            // F (F) code points. This is the end value.
2953            //
2954
2955            // 4. Exit this algorithm.
2956            return Ok(UnicodeRange {
2957                span: span!(self, span.lo),
2958                start: self.input.atom(start),
2959                end: None,
2960                raw: Some(self.input.atom(unicode_range)),
2961            });
2962        }
2963
2964        // Otherwise, interpret the consumed code points as a hexadecimal number. This
2965        // is the start value.
2966
2967        // 4. If there are no code points left in text, The end value is the same as the
2968        // start value. Exit this algorithm.
2969        if next.is_none() {
2970            return Ok(UnicodeRange {
2971                span: span!(self, span.lo),
2972                start: self.input.atom(start),
2973                end: None,
2974                raw: Some(self.input.atom(unicode_range)),
2975            });
2976        }
2977
2978        // 5. If the next code point in text is U+002D HYPHEN-MINUS (-), consume it.
2979        // Otherwise, this is an invalid <urange>, and this algorithm must exit.
2980        if next != Some('-') {
2981            return Err(Error::new(
2982                span,
2983                ErrorKind::Expected("'-' between start and end in unicode range"),
2984            ));
2985        } else {
2986            next = chars.next();
2987        }
2988
2989        // 6. Consume as many hex digits as possible from text.
2990        // If zero hex digits were consumed, or more than 6 hex digits were consumed,
2991        // this is an invalid <urange>, and this algorithm must exit. If there are any
2992        // code points left in text, this is an invalid <urange>, and this algorithm
2993        // must exit.
2994        let mut end = String::new();
2995
2996        loop {
2997            match next {
2998                Some(c) if c.is_ascii_digit() => {
2999                    end.push(c);
3000                    next = chars.next();
3001                }
3002                Some(c @ 'A'..='F') | Some(c @ 'a'..='f') => {
3003                    end.push(c);
3004                    next = chars.next();
3005                }
3006                _ => {
3007                    break;
3008                }
3009            }
3010        }
3011
3012        let len = end.len();
3013
3014        if len == 0 || len > 6 {
3015            return Err(Error::new(
3016                span,
3017                ErrorKind::Expected(
3018                    "valid length (minimum 1 or maximum 6 hex digits) in the end of unicode range",
3019                ),
3020            ));
3021        }
3022
3023        if chars.next().is_some() {
3024            return Err(Error::new(
3025                span,
3026                ErrorKind::Expected("no characters after end in unicode range"),
3027            ));
3028        }
3029
3030        return Ok(UnicodeRange {
3031            span: span!(self, span.lo),
3032            start: self.input.atom(start),
3033            end: Some(self.input.atom(end)),
3034            raw: Some(self.input.atom(unicode_range)),
3035        });
3036    }
3037}
3038
3039impl<I> Parse<CalcSum> for Parser<I>
3040where
3041    I: ParserInput,
3042{
3043    fn parse(&mut self) -> PResult<CalcSum> {
3044        let start = self.input.cur_span().lo;
3045        let mut expressions = Vec::new();
3046        let calc_product = CalcProductOrOperator::Product(self.parse()?);
3047        let mut end = match calc_product {
3048            CalcProductOrOperator::Product(ref calc_product) => calc_product.span.hi,
3049            _ => {
3050                unreachable!();
3051            }
3052        };
3053
3054        expressions.push(calc_product);
3055
3056        loop {
3057            self.input.skip_ws();
3058
3059            if is!(self, EOF) {
3060                break;
3061            }
3062
3063            match cur!(self) {
3064                tok!("+") | tok!("-") => {
3065                    let operator = CalcProductOrOperator::Operator(self.parse()?);
3066
3067                    expressions.push(operator);
3068
3069                    self.input.skip_ws();
3070
3071                    let calc_product = CalcProductOrOperator::Product(self.parse()?);
3072
3073                    end = match calc_product {
3074                        CalcProductOrOperator::Product(ref calc_product) => calc_product.span.hi,
3075                        _ => {
3076                            unreachable!();
3077                        }
3078                    };
3079
3080                    expressions.push(calc_product);
3081                }
3082                _ => {
3083                    break;
3084                }
3085            }
3086        }
3087
3088        Ok(CalcSum {
3089            span: Span::new(start, end),
3090            expressions,
3091        })
3092    }
3093}
3094
3095impl<I> Parse<CalcProduct> for Parser<I>
3096where
3097    I: ParserInput,
3098{
3099    fn parse(&mut self) -> PResult<CalcProduct> {
3100        let start = self.input.cur_span().lo;
3101        let mut expressions = Vec::new();
3102        let calc_value = CalcValueOrOperator::Value(self.parse()?);
3103        let mut end = match calc_value {
3104            CalcValueOrOperator::Value(ref calc_value) => match calc_value {
3105                CalcValue::Number(item) => item.span.hi,
3106                CalcValue::Percentage(item) => item.span.hi,
3107                CalcValue::Constant(item) => item.span.hi,
3108                CalcValue::Sum(item) => item.span.hi,
3109                CalcValue::Function(item) => item.span.hi,
3110                CalcValue::Dimension(item) => match item {
3111                    Dimension::Length(item) => item.span.hi,
3112                    Dimension::Angle(item) => item.span.hi,
3113                    Dimension::Time(item) => item.span.hi,
3114                    Dimension::Frequency(item) => item.span.hi,
3115                    Dimension::Resolution(item) => item.span.hi,
3116                    Dimension::Flex(item) => item.span.hi,
3117                    Dimension::UnknownDimension(item) => item.span.hi,
3118                },
3119            },
3120            _ => {
3121                unreachable!();
3122            }
3123        };
3124
3125        expressions.push(calc_value);
3126
3127        loop {
3128            self.input.skip_ws();
3129
3130            if is!(self, EOF) {
3131                break;
3132            }
3133
3134            match cur!(self) {
3135                tok!("*") | tok!("/") => {
3136                    let operator = CalcValueOrOperator::Operator(self.parse()?);
3137
3138                    expressions.push(operator);
3139
3140                    self.input.skip_ws();
3141
3142                    let calc_value = CalcValueOrOperator::Value(self.parse()?);
3143
3144                    end = match calc_value {
3145                        CalcValueOrOperator::Value(ref calc_value) => match calc_value {
3146                            CalcValue::Number(item) => item.span.hi,
3147                            CalcValue::Percentage(item) => item.span.hi,
3148                            CalcValue::Constant(item) => item.span.hi,
3149                            CalcValue::Sum(item) => item.span.hi,
3150                            CalcValue::Function(item) => item.span.hi,
3151                            CalcValue::Dimension(item) => match item {
3152                                Dimension::Length(item) => item.span.hi,
3153                                Dimension::Angle(item) => item.span.hi,
3154                                Dimension::Time(item) => item.span.hi,
3155                                Dimension::Frequency(item) => item.span.hi,
3156                                Dimension::Resolution(item) => item.span.hi,
3157                                Dimension::Flex(item) => item.span.hi,
3158                                Dimension::UnknownDimension(item) => item.span.hi,
3159                            },
3160                        },
3161                        _ => {
3162                            unreachable!();
3163                        }
3164                    };
3165
3166                    expressions.push(calc_value);
3167                }
3168                _ => {
3169                    break;
3170                }
3171            }
3172        }
3173
3174        Ok(CalcProduct {
3175            span: Span::new(start, end),
3176            expressions,
3177        })
3178    }
3179}
3180
3181impl<I> Parse<CalcOperator> for Parser<I>
3182where
3183    I: ParserInput,
3184{
3185    fn parse(&mut self) -> PResult<CalcOperator> {
3186        let span = self.input.cur_span();
3187
3188        match cur!(self) {
3189            tok!("+") => {
3190                bump!(self);
3191
3192                Ok(CalcOperator {
3193                    span: span!(self, span.lo),
3194                    value: CalcOperatorType::Add,
3195                })
3196            }
3197            tok!("-") => {
3198                bump!(self);
3199
3200                Ok(CalcOperator {
3201                    span: span!(self, span.lo),
3202                    value: CalcOperatorType::Sub,
3203                })
3204            }
3205            tok!("*") => {
3206                bump!(self);
3207
3208                Ok(CalcOperator {
3209                    span: span!(self, span.lo),
3210                    value: CalcOperatorType::Mul,
3211                })
3212            }
3213            tok!("/") => {
3214                bump!(self);
3215
3216                Ok(CalcOperator {
3217                    span: span!(self, span.lo),
3218                    value: CalcOperatorType::Div,
3219                })
3220            }
3221            _ => {
3222                let span = self.input.cur_span();
3223
3224                return Err(Error::new(
3225                    span,
3226                    ErrorKind::Expected("'+', '-', '*' or '/' delim tokens"),
3227                ));
3228            }
3229        }
3230    }
3231}
3232
3233impl<I> Parse<CalcValue> for Parser<I>
3234where
3235    I: ParserInput,
3236{
3237    fn parse(&mut self) -> PResult<CalcValue> {
3238        match cur!(self) {
3239            tok!("number") => Ok(CalcValue::Number(self.parse()?)),
3240            tok!("dimension") => Ok(CalcValue::Dimension(self.parse()?)),
3241            tok!("percentage") => Ok(CalcValue::Percentage(self.parse()?)),
3242            Token::Ident { value, .. } => {
3243                match &*value.to_ascii_lowercase() {
3244                    "e" | "pi" | "infinity" | "-infinity" | "nan" => {}
3245                    _ => {
3246                        let span = self.input.cur_span();
3247
3248                        return Err(Error::new(
3249                            span,
3250                            ErrorKind::Expected(
3251                                "'e', 'pi', 'infinity', '-infinity' or 'NaN', ident tokens",
3252                            ),
3253                        ));
3254                    }
3255                }
3256
3257                Ok(CalcValue::Constant(self.parse()?))
3258            }
3259            tok!("(") => {
3260                let span = self.input.cur_span();
3261
3262                expect!(self, "(");
3263
3264                self.input.skip_ws();
3265
3266                let mut calc_sum_in_parens: CalcSum = self.parse()?;
3267
3268                self.input.skip_ws();
3269
3270                expect!(self, ")");
3271
3272                calc_sum_in_parens.span = span!(self, span.lo);
3273
3274                Ok(CalcValue::Sum(calc_sum_in_parens))
3275            }
3276            tok!("function") => Ok(CalcValue::Function(self.parse()?)),
3277            _ => {
3278                let span = self.input.cur_span();
3279
3280                return Err(Error::new(
3281                    span,
3282                    ErrorKind::Expected(
3283                        "'number', 'dimension', 'percentage', 'ident', '(' or 'function' tokens",
3284                    ),
3285                ));
3286            }
3287        }
3288    }
3289}
3290
3291impl<I> Parse<FamilyName> for Parser<I>
3292where
3293    I: ParserInput,
3294{
3295    fn parse(&mut self) -> PResult<FamilyName> {
3296        match cur!(self) {
3297            tok!("string") => Ok(FamilyName::Str(self.parse()?)),
3298            tok!("ident") => {
3299                let span = self.input.cur_span();
3300
3301                let mut value = vec![self.parse()?];
3302
3303                loop {
3304                    self.input.skip_ws();
3305
3306                    if !is!(self, "ident") {
3307                        break;
3308                    }
3309
3310                    value.push(self.parse()?);
3311                }
3312
3313                Ok(FamilyName::SequenceOfCustomIdents(SequenceOfCustomIdents {
3314                    span: span!(self, span.lo),
3315                    value,
3316                }))
3317            }
3318            _ => {
3319                let span = self.input.cur_span();
3320
3321                return Err(Error::new(
3322                    span,
3323                    ErrorKind::Expected("'string' or 'ident' tokens"),
3324                ));
3325            }
3326        }
3327    }
3328}
3329
3330pub(crate) fn is_math_function(name: &Atom) -> bool {
3331    matches_eq_ignore_ascii_case!(
3332        name,
3333        "calc",
3334        "-moz-calc",
3335        "-webkit-calc",
3336        "sin",
3337        "cos",
3338        "tan",
3339        "asin",
3340        "acos",
3341        "atan",
3342        "sqrt",
3343        "exp",
3344        "abs",
3345        "sign",
3346        "min",
3347        "max",
3348        "hypot",
3349        "clamp",
3350        "round",
3351        "mod",
3352        "rem",
3353        "atan2",
3354        "pow",
3355        "log"
3356    )
3357}
3358
3359fn is_absolute_color_base_function(name: &Atom) -> bool {
3360    matches_eq_ignore_ascii_case!(
3361        name,
3362        "rgb",
3363        "rgba",
3364        "hsl",
3365        "hsla",
3366        "hwb",
3367        "lab",
3368        "lch",
3369        "oklab",
3370        "oklch",
3371        "color",
3372        "color-mix",
3373        "color-contrast"
3374    )
3375}
3376
3377fn is_system_color(name: &Atom) -> bool {
3378    matches_eq_ignore_ascii_case!(
3379        name,
3380        "canvas",
3381        "canvastext",
3382        "linktext",
3383        "visitedtext",
3384        "activetext",
3385        "buttonface",
3386        "buttontext",
3387        "buttonborder",
3388        "field",
3389        "fieldtext",
3390        "highlight",
3391        "highlighttext",
3392        "selecteditem",
3393        "selecteditemtext",
3394        "mark",
3395        "marktext",
3396        "graytext",
3397        // Deprecated
3398        "activeborder",
3399        "activecaption",
3400        "appWorkspace",
3401        "background",
3402        "buttonhighlight",
3403        "buttonshadow",
3404        "captiontext",
3405        "inactiveborder",
3406        "inactivecaption",
3407        "inactivecaptiontext",
3408        "infobackground",
3409        "infotext",
3410        "menu",
3411        "menutext",
3412        "scrollbar",
3413        "threeddarkshadow",
3414        "threedface",
3415        "threedhighlight",
3416        "threedlightshadow",
3417        "threedshadow",
3418        "window",
3419        "windowframe",
3420        "windowtext",
3421        // Mozilla System Color Extensions
3422        "-moz-buttondefault",
3423        "-moz-buttonhoverface",
3424        "-moz-buttonhovertext",
3425        "-moz-cellhighlight",
3426        "-moz-cellhighlighttext",
3427        "-moz-combobox",
3428        "-moz-comboboxtext",
3429        "-moz-dialog",
3430        "-moz-dialogtext",
3431        "-moz-dragtargetzone",
3432        "-moz-eventreerow",
3433        "-moz-html-cellhighlight",
3434        "-moz-html-cellhighlighttext",
3435        "-moz-mac-accentdarkestshadow",
3436        "-moz-mac-accentdarkshadow",
3437        "-moz-mac-accentface",
3438        "-moz-mac-accentlightesthighlight",
3439        "-moz-mac-accentlightshadow",
3440        "-moz-mac-accentregularhighlight",
3441        "-moz-mac-accentregularshadow",
3442        "-moz-mac-chrome-active",
3443        "-moz-mac-chrome-inactive",
3444        "-moz-mac-focusring",
3445        "-moz-mac-menuselect",
3446        "-moz-mac-menushadow",
3447        "-moz-mac-menutextselect",
3448        "-moz-menuhover",
3449        "-moz-menuhovertext",
3450        "-moz-menubartext",
3451        "-moz-menubarhovertext",
3452        "-moz-nativehyperlinktext",
3453        "-moz-oddtreerow",
3454        "-moz-win-communicationstext",
3455        "-moz-win-mediatext",
3456        "-moz-win-accentcolor",
3457        "-moz-win-accentcolortext",
3458        // Mozilla Color Preference Extensions
3459        "-moz-activehyperlinktext",
3460        "-moz-default-background-color",
3461        "-moz-default-color",
3462        "-moz-hyperlinktext",
3463        "-moz-visitedhyperlinktext"
3464    )
3465}
3466
3467fn is_named_color(name: &Atom) -> bool {
3468    matches_eq_ignore_ascii_case!(
3469        name,
3470        "aliceblue",
3471        "antiquewhite",
3472        "aqua",
3473        "aquamarine",
3474        "azure",
3475        "beige",
3476        "bisque",
3477        "black",
3478        "blanchedalmond",
3479        "blue",
3480        "blueviolet",
3481        "brown",
3482        "burlywood",
3483        "cadetblue",
3484        "chartreuse",
3485        "chocolate",
3486        "coral",
3487        "cornflowerblue",
3488        "cornsilk",
3489        "crimson",
3490        "cyan",
3491        "darkblue",
3492        "darkcyan",
3493        "darkgoldenrod",
3494        "darkgray",
3495        "darkgreen",
3496        "darkgrey",
3497        "darkkhaki",
3498        "darkmagenta",
3499        "darkolivegreen",
3500        "darkorange",
3501        "darkorchid",
3502        "darkred",
3503        "darksalmon",
3504        "darkseagreen",
3505        "darkslateblue",
3506        "darkslategray",
3507        "darkslategrey",
3508        "darkturquoise",
3509        "darkviolet",
3510        "deeppink",
3511        "deepskyblue",
3512        "dimgray",
3513        "dimgrey",
3514        "dodgerblue",
3515        "firebrick",
3516        "floralwhite",
3517        "forestgreen",
3518        "fuchsia",
3519        "gainsboro",
3520        "ghostwhite",
3521        "gold",
3522        "goldenrod",
3523        "gray",
3524        "green",
3525        "greenyellow",
3526        "grey",
3527        "honeydew",
3528        "hotpink",
3529        "indianred",
3530        "indigo",
3531        "ivory",
3532        "khaki",
3533        "lavender",
3534        "lavenderblush",
3535        "lawngreen",
3536        "lemonchiffon",
3537        "lightblue",
3538        "lightcoral",
3539        "lightcyan",
3540        "lightgoldenrodyellow",
3541        "lightgray",
3542        "lightgreen",
3543        "lightgrey",
3544        "lightpink",
3545        "lightsalmon",
3546        "lightseagreen",
3547        "lightskyblue",
3548        "lightslategray",
3549        "lightslategrey",
3550        "lightsteelblue",
3551        "lightyellow",
3552        "lime",
3553        "limegreen",
3554        "linen",
3555        "magenta",
3556        "maroon",
3557        "mediumaquamarine",
3558        "mediumblue",
3559        "mediumorchid",
3560        "mediumpurple",
3561        "mediumseagreen",
3562        "mediumslateblue",
3563        "mediumspringgreen",
3564        "mediumturquoise",
3565        "mediumvioletred",
3566        "midnightblue",
3567        "mintcream",
3568        "mistyrose",
3569        "moccasin",
3570        "navajowhite",
3571        "navy",
3572        "oldlace",
3573        "olive",
3574        "olivedrab",
3575        "orange",
3576        "orangered",
3577        "orchid",
3578        "palegoldenrod",
3579        "palegreen",
3580        "paleturquoise",
3581        "palevioletred",
3582        "papayawhip",
3583        "peachpuff",
3584        "peru",
3585        "pink",
3586        "plum",
3587        "powderblue",
3588        "purple",
3589        "rebeccapurple",
3590        "red",
3591        "rosybrown",
3592        "royalblue",
3593        "saddlebrown",
3594        "salmon",
3595        "sandybrown",
3596        "seagreen",
3597        "seashell",
3598        "sienna",
3599        "silver",
3600        "skyblue",
3601        "slateblue",
3602        "slategray",
3603        "slategrey",
3604        "snow",
3605        "springgreen",
3606        "steelblue",
3607        "tan",
3608        "teal",
3609        "thistle",
3610        "tomato",
3611        "turquoise",
3612        "violet",
3613        "wheat",
3614        "white",
3615        "whitesmoke",
3616        "yellow",
3617        "yellowgreen"
3618    )
3619}
3620
3621fn is_length_unit(unit: &Atom) -> bool {
3622    matches_eq_ignore_ascii_case!(
3623        unit, "em", "rem", "ex", "rex", "cap", "rcap", "ch", "rch", "ic", "ric", "lh", "rlh",
3624        //  Viewport-percentage Lengths
3625        "vw", "svw", "lvw", "dvw", "vh", "svh", "lvh", "dvh", "vi", "svi", "lvi", "dvi", "vb",
3626        "svb", "lvb", "dvb", "vmin", "svmin", "lvmin", "dvmin", "vmax", "svmax", "lvmax", "dvmax",
3627        // Absolute lengths
3628        "cm", "mm", "q", "in", "pc", "pt", "px", "mozmm"
3629    )
3630}
3631
3632fn is_container_lengths_unit(unit: &Atom) -> bool {
3633    matches_eq_ignore_ascii_case!(unit, "cqw", "cqh", "cqi", "cqb", "cqmin", "cqmax")
3634}
3635
3636fn is_angle_unit(unit: &Atom) -> bool {
3637    matches_eq_ignore_ascii_case!(unit, "deg", "grad", "rad", "turn")
3638}
3639
3640fn is_time_unit(unit: &Atom) -> bool {
3641    matches_eq_ignore_ascii_case!(unit, "s", "ms")
3642}
3643
3644fn is_frequency_unit(unit: &Atom) -> bool {
3645    matches_eq_ignore_ascii_case!(unit, "hz", "khz")
3646}
3647
3648fn is_resolution_unit(unit: &Atom) -> bool {
3649    matches_eq_ignore_ascii_case!(unit, "dpi", "dpcm", "dppx", "x")
3650}
3651
3652fn is_flex_unit(unit: &Atom) -> bool {
3653    matches_eq_ignore_ascii_case!(unit, "fr")
3654}