raffia/parser/at_rule/
layer.rs1use 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
12impl<'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
36impl<'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}