Skip to main content

oxc_css_parser/parser/at_rule/
scope.rs

1use super::Parser;
2use crate::{
3    Parse,
4    ast::*,
5    bump,
6    error::{Error, ErrorKind, PResult},
7    expect, peek,
8    pos::Span,
9    tokenizer::{Token, TokenWithSpan},
10};
11
12impl<'a> Parse<'a> for ScopeEnd<'a> {
13    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
14        let to_span = match bump!(input) {
15            TokenWithSpan { token: Token::Ident(ident), span }
16                if ident.name().eq_ignore_ascii_case("to") =>
17            {
18                span
19            }
20            TokenWithSpan { span, .. } => {
21                return Err(Error { kind: ErrorKind::ExpectScopeTo, span });
22            }
23        };
24
25        let (_, lparen_span) = expect!(input, LParen);
26        let selector = input.parse()?;
27        let (_, Span { end, .. }) = expect!(input, RParen);
28
29        let span = Span { start: to_span.start, end };
30        Ok(ScopeEnd { to_span, lparen_span, selector, span })
31    }
32}
33
34// https://drafts.csswg.org/css-cascade-6/#scope-syntax
35impl<'a> Parse<'a> for ScopePrelude<'a> {
36    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
37        let start = if let Token::LParen(..) = peek!(input).token {
38            Some(input.parse::<ScopeStart>()?)
39        } else {
40            None
41        };
42        let end = match &peek!(input).token {
43            Token::Ident(ident) if ident.name().eq_ignore_ascii_case("to") => {
44                Some(input.parse::<ScopeEnd>()?)
45            }
46            _ => None,
47        };
48
49        match (start, end) {
50            (Some(start), Some(end)) => {
51                let span = Span { start: start.span.start, end: end.span.end };
52                Ok(ScopePrelude::Both(ScopeStartWithEnd { start, end, span }))
53            }
54            (Some(start), None) => Ok(ScopePrelude::StartOnly(start)),
55            (None, Some(end)) => Ok(ScopePrelude::EndOnly(end)),
56            (None, None) => {
57                use crate::{token::LParen, tokenizer::TokenSymbol};
58                let TokenWithSpan { token, span } = bump!(input);
59                Err(Error { kind: ErrorKind::Unexpected(LParen::symbol(), token.symbol()), span })
60            }
61        }
62    }
63}
64
65impl<'a> Parse<'a> for ScopeStart<'a> {
66    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
67        let (_, Span { start, .. }) = expect!(input, LParen);
68        let selector = input.parse()?;
69        let (_, Span { end, .. }) = expect!(input, RParen);
70
71        Ok(ScopeStart { selector, span: Span { start, end } })
72    }
73}