Skip to main content

oxc_css_parser/parser/at_rule/
scope.rs

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