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> {
12 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
13 match &input.cursor.peek()?.token {
14 Token::Ident(token) if token.name().eq_ignore_ascii_case("not") => {
15 let keyword = input.parse::<Ident>()?;
16 let condition = input.parse::<SupportsInParens>()?;
17 let span = Span { start: keyword.span.start, end: condition.span().end };
18 Ok(SupportsCondition {
19 conditions: input.vec1(SupportsConditionKind::Not(SupportsNot {
20 keyword,
21 condition,
22 span: span.clone(),
23 })),
24 span,
25 })
26 }
27 _ => {
28 let first = input.parse::<SupportsInParens>()?;
29 let mut span = first.span().clone();
30 let mut conditions = input.vec1(SupportsConditionKind::SupportsInParens(first));
31 while let Token::Ident(ident) = &input.cursor.peek()?.token {
32 let name = ident.name();
33 if name.eq_ignore_ascii_case("and") {
34 let ident = input.parse::<Ident>()?;
35 let condition = input.parse::<SupportsInParens>()?;
36 let span = Span { start: ident.span.start, end: condition.span().end };
37 conditions.push(SupportsConditionKind::And(SupportsAnd {
38 keyword: ident,
39 condition,
40 span,
41 }));
42 } else if name.eq_ignore_ascii_case("or") {
43 let ident = input.parse::<Ident>()?;
44 let condition = input.parse::<SupportsInParens>()?;
45 let span = Span { start: ident.span.start, end: condition.span().end };
46 conditions.push(SupportsConditionKind::Or(SupportsOr {
47 keyword: ident,
48 condition,
49 span,
50 }));
51 } else {
52 break;
53 }
54 }
55 if let Some(last) = conditions.last() {
56 span.end = last.span().end;
57 }
58 Ok(SupportsCondition { conditions, span })
59 }
60 }
61 }
62}
63
64impl<'a> Parse<'a> for SupportsInParens<'a> {
65 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
66 match input.cursor.peek()? {
67 TokenWithSpan { token: Token::LParen(..), .. } => input
68 .try_parse(|parser| {
69 parser.parse::<SupportsDecl>().map(|supports_decl| {
70 let span = supports_decl.span.clone();
71 SupportsInParens {
72 kind: SupportsInParensKind::Feature(parser.alloc(supports_decl)),
73 span,
74 }
75 })
76 })
77 .or_else(|_| {
78 input.try_parse(|parser| {
79 let (_, Span { start, .. }) = parser.cursor.expect_l_paren()?;
80 let condition = parser.parse::<SupportsCondition>()?;
81 let (_, Span { end, .. }) = parser.cursor.expect_r_paren()?;
82 Ok(SupportsInParens {
83 kind: SupportsInParensKind::SupportsCondition(condition),
84 span: Span { start, end },
85 })
86 })
87 })
88 .or_else(|_| {
89 let (_, Span { start, .. }) = input.cursor.expect_l_paren()?;
92 let tokens = input.parse_tokens_in_parens()?;
93 let (_, Span { end, .. }) = input.cursor.expect_r_paren()?;
94 Ok(SupportsInParens {
95 kind: SupportsInParensKind::GeneralEnclosed(tokens),
96 span: Span { start, end },
97 })
98 }),
99 TokenWithSpan { token: Token::Ident(..) | Token::HashLBrace(..), .. } => {
103 let name = input.parse::<InterpolableIdent>()?;
104 let name_end = name.span().end;
105 match name {
106 InterpolableIdent::Literal(function_ident)
107 if function_ident.name.eq_ignore_ascii_case("selector") =>
108 {
109 input.cursor.expect_l_paren()?;
110 let selector_list = input.parse::<SelectorList>()?;
111 input.cursor.expect_r_paren()?;
112 let span = selector_list.span.clone();
113 Ok(SupportsInParens {
114 kind: SupportsInParensKind::Selector(selector_list),
115 span,
116 })
117 }
118 name => {
119 let glued_lparen = matches!(
120 input.cursor.peek()?,
121 TokenWithSpan { token: Token::LParen(..), span }
122 if span.start == name_end
123 );
124 let pure_interpolation = matches!(
128 &name,
129 InterpolableIdent::SassInterpolated(interpolation)
130 if matches!(
131 interpolation.elements.as_slice(),
132 [SassInterpolatedIdentElement::Expression(..)]
133 )
134 );
135 if glued_lparen {
136 let function = input.parse_raw_function(name)?;
139 let span = function.span.clone();
140 Ok(SupportsInParens {
141 kind: SupportsInParensKind::Function(function),
142 span,
143 })
144 } else if pure_interpolation {
145 let span = name.span().clone();
146 Ok(SupportsInParens {
147 kind: SupportsInParensKind::Interpolation(name),
148 span,
149 })
150 } else {
151 let TokenWithSpan { token, span } = input.cursor.peek()?;
152 Err(Error {
153 kind: ErrorKind::Unexpected("'('", token.symbol()),
154 span: span.clone(),
155 })
156 }
157 }
158 }
159 }
160 TokenWithSpan { token, span } => Err(Error {
161 kind: ErrorKind::Unexpected("'('", token.symbol()),
162 span: span.clone(),
163 }),
164 }
165 }
166}
167
168impl<'a> Parse<'a> for SupportsDecl<'a> {
169 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
170 let start = input.cursor.expect_l_paren()?.1.start;
171 let decl = input.parse()?;
172 let end = input.cursor.expect_r_paren()?.1.end;
173 Ok(SupportsDecl { decl, span: Span { start, end } })
174 }
175}