oxc_css_parser/parser/at_rule/
supports.rs1use super::Parser;
2use crate::{
3 Parse, arena_box, arena_vec,
4 ast::*,
5 error::{Error, ErrorKind, PResult},
6 expect, peek,
7 pos::{Span, Spanned},
8 tokenizer::{Token, TokenWithSpan},
9};
10
11impl<'a> Parse<'a> for SupportsCondition<'a> {
13 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
14 match &peek!(input).token {
15 Token::Ident(token) if token.name().eq_ignore_ascii_case("not") => {
16 let keyword = input.parse::<Ident>()?;
17 let condition = input.parse::<SupportsInParens>()?;
18 let span = Span { start: keyword.span.start, end: condition.span().end };
19 Ok(SupportsCondition {
20 conditions: arena_vec!(input; SupportsConditionKind::Not(SupportsNot {
21 keyword,
22 condition,
23 span: span.clone(),
24 })),
25 span,
26 })
27 }
28 _ => {
29 let first = input.parse::<SupportsInParens>()?;
30 let mut span = first.span().clone();
31 let mut conditions =
32 arena_vec!(input; SupportsConditionKind::SupportsInParens(first));
33 while let Token::Ident(ident) = &peek!(input).token {
34 let name = ident.name();
35 if name.eq_ignore_ascii_case("and") {
36 let ident = input.parse::<Ident>()?;
37 let condition = input.parse::<SupportsInParens>()?;
38 let span = Span { start: ident.span.start, end: condition.span().end };
39 conditions.push(SupportsConditionKind::And(SupportsAnd {
40 keyword: ident,
41 condition,
42 span,
43 }));
44 } else if name.eq_ignore_ascii_case("or") {
45 let ident = input.parse::<Ident>()?;
46 let condition = input.parse::<SupportsInParens>()?;
47 let span = Span { start: ident.span.start, end: condition.span().end };
48 conditions.push(SupportsConditionKind::Or(SupportsOr {
49 keyword: ident,
50 condition,
51 span,
52 }));
53 } else {
54 break;
55 }
56 }
57 if let Some(last) = conditions.last() {
58 span.end = last.span().end;
59 }
60 Ok(SupportsCondition { conditions, span })
61 }
62 }
63 }
64}
65
66impl<'a> Parse<'a> for SupportsInParens<'a> {
67 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
68 match peek!(input) {
69 TokenWithSpan { token: Token::LParen(..), .. } => input
70 .try_parse(|parser| {
71 parser.parse::<SupportsDecl>().map(|supports_decl| {
72 let span = supports_decl.span.clone();
73 SupportsInParens {
74 kind: SupportsInParensKind::Feature(arena_box!(parser, supports_decl)),
75 span,
76 }
77 })
78 })
79 .or_else(|_| {
80 input.try_parse(|parser| {
81 let (_, Span { start, .. }) = expect!(parser, LParen);
82 let condition = parser.parse::<SupportsCondition>()?;
83 let (_, Span { end, .. }) = expect!(parser, RParen);
84 Ok(SupportsInParens {
85 kind: SupportsInParensKind::SupportsCondition(condition),
86 span: Span { start, end },
87 })
88 })
89 })
90 .or_else(|_| {
91 let (_, Span { start, .. }) = expect!(input, LParen);
94 let tokens = input.parse_tokens_in_parens()?;
95 let (_, Span { end, .. }) = expect!(input, RParen);
96 Ok(SupportsInParens {
97 kind: SupportsInParensKind::GeneralEnclosed(tokens),
98 span: Span { start, end },
99 })
100 }),
101 TokenWithSpan { token: Token::Ident(..), .. } => {
102 let function_ident = input.parse::<Ident>()?;
103 if function_ident.name.eq_ignore_ascii_case("selector") {
104 expect!(input, LParen);
105 let selector_list = input.parse::<SelectorList>()?;
106 expect!(input, RParen);
107 let span = selector_list.span.clone();
108 Ok(SupportsInParens {
109 kind: SupportsInParensKind::Selector(selector_list),
110 span,
111 })
112 } else {
113 let function =
114 input.parse_function(InterpolableIdent::Literal(function_ident))?;
115 let span = function.span.clone();
116 Ok(SupportsInParens { kind: SupportsInParensKind::Function(function), span })
117 }
118 }
119 TokenWithSpan { token, span } => Err(Error {
120 kind: ErrorKind::Unexpected("'('", token.symbol()),
121 span: span.clone(),
122 }),
123 }
124 }
125}
126
127impl<'a> Parse<'a> for SupportsDecl<'a> {
128 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
129 let start = expect!(input, LParen).1.start;
130 let decl = input.parse()?;
131 let end = expect!(input, RParen).1.end;
132 Ok(SupportsDecl { decl, span: Span { start, end } })
133 }
134}