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<'cmt, 's: 'cmt> Parse<'cmt, 's> for ScopeEnd<'s> {
13    fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
14        let to_span = match bump!(input) {
15            TokenWithSpan {
16                token: Token::Ident(ident),
17                span,
18            } if ident.name().eq_ignore_ascii_case("to") => span,
19            TokenWithSpan { span, .. } => {
20                return Err(Error {
21                    kind: ErrorKind::ExpectScopeTo,
22                    span,
23                });
24            }
25        };
26
27        let (_, lparen_span) = expect!(input, LParen);
28        let selector = input.parse()?;
29        let (_, Span { end, .. }) = expect!(input, RParen);
30
31        let span = Span {
32            start: to_span.start,
33            end,
34        };
35        Ok(ScopeEnd {
36            to_span,
37            lparen_span,
38            selector,
39            span,
40        })
41    }
42}
43
44// https://drafts.csswg.org/css-cascade-6/#scope-syntax
45impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for ScopePrelude<'s> {
46    fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
47        let start = if let Token::LParen(..) = peek!(input).token {
48            Some(input.parse::<ScopeStart>()?)
49        } else {
50            None
51        };
52        let end = match &peek!(input).token {
53            Token::Ident(ident) if ident.name().eq_ignore_ascii_case("to") => {
54                Some(input.parse::<ScopeEnd>()?)
55            }
56            _ => None,
57        };
58
59        match (start, end) {
60            (Some(start), Some(end)) => {
61                let span = Span {
62                    start: start.span.start,
63                    end: end.span.end,
64                };
65                Ok(ScopePrelude::Both(ScopeStartWithEnd { start, end, span }))
66            }
67            (Some(start), None) => Ok(ScopePrelude::StartOnly(start)),
68            (None, Some(end)) => Ok(ScopePrelude::EndOnly(end)),
69            (None, None) => {
70                use crate::{token::LParen, tokenizer::TokenSymbol};
71                let TokenWithSpan { token, span } = bump!(input);
72                Err(Error {
73                    kind: ErrorKind::Unexpected(LParen::symbol(), token.symbol()),
74                    span,
75                })
76            }
77        }
78    }
79}
80
81impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for ScopeStart<'s> {
82    fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
83        let (_, Span { start, .. }) = expect!(input, LParen);
84        let selector = input.parse()?;
85        let (_, Span { end, .. }) = expect!(input, RParen);
86
87        Ok(ScopeStart {
88            selector,
89            span: Span { start, end },
90        })
91    }
92}