raffia/parser/at_rule/
layer.rs

1use super::Parser;
2use crate::{
3    ast::*,
4    bump, eat,
5    error::{Error, PResult},
6    peek,
7    pos::{Span, Spanned},
8    tokenizer::{Token, TokenWithSpan},
9    util, Parse,
10};
11
12// https://drafts.csswg.org/css-cascade-5/#layering
13impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for LayerNames<'s> {
14    fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
15        let first = input.parse::<LayerName>()?;
16        let mut span = first.span.clone();
17
18        let mut names = vec![first];
19        let mut comma_spans = vec![];
20        while let Some((_, comma_span)) = eat!(input, Comma) {
21            comma_spans.push(comma_span);
22            names.push(input.parse()?);
23        }
24
25        if let Some(last) = names.last() {
26            span.end = last.span.end;
27        }
28        Ok(LayerNames {
29            names,
30            comma_spans,
31            span,
32        })
33    }
34}
35
36// https://drafts.csswg.org/css-cascade-5/#layer-names
37impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for LayerName<'s> {
38    fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
39        let first = input.parse::<InterpolableIdent>()?;
40        let start = first.span().start;
41        let mut end = first.span().end;
42
43        let mut idents = vec![first];
44        while let TokenWithSpan {
45            token: Token::Dot(..),
46            span,
47        } = peek!(input)
48        {
49            if span.start == end {
50                let span = bump!(input).span;
51                let ident = input.parse::<InterpolableIdent>()?;
52                util::assert_no_ws_or_comment(&span, ident.span())?;
53                end = ident.span().end;
54                idents.push(ident);
55            } else {
56                break;
57            }
58        }
59
60        let invalid_ident = idents.iter().find(|ident| match &ident {
61            InterpolableIdent::Literal(ident) => util::is_css_wide_keyword(&ident.name),
62            _ => false,
63        });
64        if let Some(invalid_ident) = invalid_ident {
65            input.recoverable_errors.push(Error {
66                kind: crate::error::ErrorKind::CSSWideKeywordDisallowed,
67                span: invalid_ident.span().clone(),
68            });
69        }
70
71        let span = Span { start, end };
72        Ok(LayerName { idents, span })
73    }
74}