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