oxc_css_parser/parser/at_rule/
supports.rs1use super::Parser;
2use crate::{
3 Parse,
4 ast::*,
5 error::{Error, ErrorKind, PResult},
6 pos::Span,
7 tokenizer::{Token, TokenWithSpan},
8};
9
10impl<'a> Parse<'a> for SupportsCondition<'a> {
16 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
17 match &input.cursor.peek()?.token {
18 Token::Ident(token) if token.name().eq_ignore_ascii_case("not") => {
19 let keyword = input.parse::<Ident>()?;
20 let condition = input.parse::<SupportsInParens>()?;
21 let span = Span { start: keyword.span.start, end: condition.span().end };
22 Ok(SupportsCondition {
23 conditions: input.vec1(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 = input.vec1(SupportsConditionKind::SupportsInParens(first));
35 while let Token::Ident(ident) = &input.cursor.peek()?.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 { start: ident.span.start, end: condition.span().end };
41 conditions.push(SupportsConditionKind::And(SupportsAnd {
42 keyword: ident,
43 condition,
44 span,
45 }));
46 } else if name.eq_ignore_ascii_case("or") {
47 let ident = input.parse::<Ident>()?;
48 let condition = input.parse::<SupportsInParens>()?;
49 let span = Span { start: ident.span.start, end: condition.span().end };
50 conditions.push(SupportsConditionKind::Or(SupportsOr {
51 keyword: ident,
52 condition,
53 span,
54 }));
55 } else {
56 break;
57 }
58 }
59 if let Some(last) = conditions.last() {
60 span.end = last.span().end;
61 }
62 Ok(SupportsCondition { conditions, span })
63 }
64 }
65 }
66}
67
68impl<'a> Parse<'a> for SupportsInParens<'a> {
74 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
75 match input.cursor.peek()? {
76 TokenWithSpan { token: Token::LParen(..), .. } => input
77 .try_parse(|parser| {
78 parser.parse::<SupportsDecl>().map(|supports_decl| {
79 let span = supports_decl.span.clone();
80 SupportsInParens {
81 kind: SupportsInParensKind::Feature(parser.alloc(supports_decl)),
82 span,
83 }
84 })
85 })
86 .or_else(|_| {
87 input.try_parse(|parser| {
88 let (_, Span { start, .. }) = parser.cursor.expect_l_paren()?;
89 let condition = parser.parse::<SupportsCondition>()?;
90 let (_, Span { end, .. }) = parser.cursor.expect_r_paren()?;
91 Ok(SupportsInParens {
92 kind: SupportsInParensKind::SupportsCondition(condition),
93 span: Span { start, end },
94 })
95 })
96 })
97 .or_else(|_| {
98 let (_, Span { start, .. }) = input.cursor.expect_l_paren()?;
101 let tokens = input.parse_tokens_in_parens()?;
102 let (_, Span { end, .. }) = input.cursor.expect_r_paren()?;
103 Ok(SupportsInParens {
104 kind: SupportsInParensKind::GeneralEnclosed(tokens),
105 span: Span { start, end },
106 })
107 }),
108 TokenWithSpan { token: Token::Ident(..) | Token::HashLBrace(..), .. } => {
112 let name = input.parse::<InterpolableIdent>()?;
113 let name_end = name.span().end;
114 match name {
115 InterpolableIdent::Literal(function_ident)
116 if function_ident.name.eq_ignore_ascii_case("selector") =>
117 {
118 input.cursor.expect_l_paren()?;
119 let selector_list = input.parse::<SelectorList>()?;
120 input.cursor.expect_r_paren()?;
121 let span = selector_list.span.clone();
122 Ok(SupportsInParens {
123 kind: SupportsInParensKind::Selector(selector_list),
124 span,
125 })
126 }
127 name => {
128 let glued_lparen = matches!(
129 input.cursor.peek()?,
130 TokenWithSpan { token: Token::LParen(..), span }
131 if span.start == name_end
132 );
133 let pure_interpolation = matches!(
137 &name,
138 InterpolableIdent::SassInterpolated(interpolation)
139 if matches!(
140 interpolation.elements.as_slice(),
141 [SassInterpolatedIdentElement::Expression(..)]
142 )
143 );
144 if glued_lparen {
145 let function = input.parse_raw_function(name)?;
148 let span = function.span.clone();
149 Ok(SupportsInParens {
150 kind: SupportsInParensKind::Function(function),
151 span,
152 })
153 } else if pure_interpolation {
154 let span = name.span().clone();
155 Ok(SupportsInParens {
156 kind: SupportsInParensKind::Interpolation(name),
157 span,
158 })
159 } else {
160 let TokenWithSpan { token, span } = input.cursor.peek()?;
161 Err(Error {
162 kind: ErrorKind::Unexpected("'('", token.symbol()),
163 span: span.clone(),
164 })
165 }
166 }
167 }
168 }
169 TokenWithSpan { token, span } => Err(Error {
170 kind: ErrorKind::Unexpected("'('", token.symbol()),
171 span: span.clone(),
172 }),
173 }
174 }
175}
176
177impl<'a> Parse<'a> for SupportsDecl<'a> {
182 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
183 let start = input.cursor.expect_l_paren()?.1.start;
184 let decl = input.parse()?;
185 let end = input.cursor.expect_r_paren()?.1.end;
186 Ok(SupportsDecl { decl, span: Span { start, end } })
187 }
188}