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 if input.cursor.peek()?.is_ident_name_eq_ignore_ascii_case(input.source, "not") {
18 let keyword = input.parse::<Ident>()?;
19 let condition = input.parse::<SupportsInParens>()?;
20 let span = Span { start: keyword.span.start, end: condition.span().end };
21 Ok(SupportsCondition {
22 conditions: input.vec1(SupportsConditionKind::Not(SupportsNot {
23 keyword,
24 condition,
25 span,
26 })),
27 span,
28 })
29 } else {
30 let first = input.parse::<SupportsInParens>()?;
31 let mut span = *first.span();
32 let mut conditions = input.vec1(SupportsConditionKind::SupportsInParens(first));
33 while input.cursor.peek()?.ident(input.source).is_some() {
34 if input.cursor.peek()?.is_ident_name_eq_ignore_ascii_case(input.source, "and") {
35 let ident = input.parse::<Ident>()?;
36 let condition = input.parse::<SupportsInParens>()?;
37 let span = Span { start: ident.span.start, end: condition.span().end };
38 conditions.push(SupportsConditionKind::And(SupportsAnd {
39 keyword: ident,
40 condition,
41 span,
42 }));
43 } else if input
44 .cursor
45 .peek()?
46 .is_ident_name_eq_ignore_ascii_case(input.source, "or")
47 {
48 let ident = input.parse::<Ident>()?;
49 let condition = input.parse::<SupportsInParens>()?;
50 let span = Span { start: ident.span.start, end: condition.span().end };
51 conditions.push(SupportsConditionKind::Or(SupportsOr {
52 keyword: ident,
53 condition,
54 span,
55 }));
56 } else {
57 break;
58 }
59 }
60 if let Some(last) = conditions.last() {
61 span.end = last.span().end;
62 }
63 Ok(SupportsCondition { conditions, span })
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;
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;
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;
149 Ok(SupportsInParens {
150 kind: SupportsInParensKind::Function(function),
151 span,
152 })
153 } else if pure_interpolation {
154 let span = *name.span();
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,
164 })
165 }
166 }
167 }
168 }
169 TokenWithSpan { token, span } => {
170 Err(Error { kind: ErrorKind::Unexpected("'('", token.symbol()), span: *span })
171 }
172 }
173 }
174}
175
176impl<'a> Parse<'a> for SupportsDecl<'a> {
181 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
182 let start = input.cursor.expect_l_paren()?.1.start;
183 let decl = input.parse()?;
184 let end = input.cursor.expect_r_paren()?.1.end;
185 Ok(SupportsDecl { decl, span: Span { start, end } })
186 }
187}