1use super::{
2 state::{ParserState, QualifiedRuleContext},
3 Parser,
4};
5use crate::{
6 ast::*,
7 bump, eat,
8 error::{Error, ErrorKind, PResult},
9 expect, peek,
10 pos::{Span, Spanned},
11 tokenizer::{Token, TokenWithSpan},
12 util::PairedToken,
13 Parse, Syntax,
14};
15
16impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for Declaration<'s> {
17 fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
18 let name = input
19 .with_state(ParserState {
20 qualified_rule_ctx: Some(QualifiedRuleContext::DeclarationName),
21 ..input.state
22 })
23 .parse::<InterpolableIdent>()?;
24
25 let less_property_merge = if input.syntax == Syntax::Less {
26 input.parse()?
27 } else {
28 None
29 };
30
31 let (_, colon_span) = expect!(input, Colon);
32 let value = {
33 let mut parser = input.with_state(ParserState {
34 qualified_rule_ctx: Some(QualifiedRuleContext::DeclarationValue),
35 ..input.state
36 });
37 match &name {
38 InterpolableIdent::Literal(ident)
39 if ident.name.starts_with("--")
40 || ident.name.eq_ignore_ascii_case("filter")
41 && matches!(
42 &peek!(parser).token,
43 Token::Ident(ident) if ident.name().eq_ignore_ascii_case("progid")
46 ) =>
47 'value: {
48 if parser.options.try_parsing_value_in_custom_property {
49 if let Ok(values) = parser.try_parse(Parser::parse_declaration_value) {
50 break 'value values;
51 }
52 }
53
54 let mut values = Vec::with_capacity(3);
55 let mut pairs = Vec::with_capacity(1);
56 loop {
57 match &peek!(parser).token {
58 Token::Dedent(..) | Token::Linebreak(..) | Token::Eof(..) => break,
59 Token::Semicolon(..) => {
60 if pairs.is_empty() {
61 break;
62 }
63 }
64 Token::LParen(..) => {
65 pairs.push(PairedToken::Paren);
66 }
67 Token::RParen(..) => {
68 if let Some(PairedToken::Paren) = pairs.pop() {
69 } else {
70 break;
71 }
72 }
73 Token::LBracket(..) => {
74 pairs.push(PairedToken::Bracket);
75 }
76 Token::RBracket(..) => {
77 if let Some(PairedToken::Bracket) = pairs.pop() {
78 } else {
79 break;
80 }
81 }
82 Token::LBrace(..) | Token::HashLBrace(..) => {
83 pairs.push(PairedToken::Brace);
84 }
85 Token::RBrace(..) => {
86 if let Some(PairedToken::Brace) = pairs.pop() {
87 } else {
88 break;
89 }
90 }
91 _ => {}
92 }
93 values.push(ComponentValue::TokenWithSpan(bump!(parser)));
94 }
95 values
96 }
97 _ => parser.parse_declaration_value()?,
98 }
99 };
100
101 let important = if let Token::Exclamation(..) = &peek!(input).token {
102 input.parse::<ImportantAnnotation>().map(Some)?
103 } else {
104 None
105 };
106
107 let span = Span {
108 start: name.span().start,
109 end: if let Some(important) = &important {
110 important.span.end
111 } else if let Some(last) = value.last() {
112 last.span().end
113 } else {
114 colon_span.end
115 },
116 };
117 Ok(Declaration {
118 name,
119 colon_span,
120 value,
121 important,
122 less_property_merge,
123 span,
124 })
125 }
126}
127
128impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for ImportantAnnotation<'s> {
129 fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
130 let (_, span) = expect!(input, Exclamation);
131 let ident: Ident = input.parse::<Ident>()?;
132 let span = Span {
133 start: span.start,
134 end: ident.span.end,
135 };
136 if ident.name.eq_ignore_ascii_case("important") {
137 Ok(ImportantAnnotation { ident, span })
138 } else {
139 Err(Error {
140 kind: ErrorKind::ExpectImportantAnnotation,
141 span,
142 })
143 }
144 }
145}
146
147impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for QualifiedRule<'s> {
148 fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
149 let selector_list = input
150 .with_state(ParserState {
151 qualified_rule_ctx: Some(QualifiedRuleContext::Selector),
152 ..input.state
153 })
154 .parse::<SelectorList>()?;
155 let block = input.parse::<SimpleBlock>()?;
156 let span = Span {
157 start: selector_list.span.start,
158 end: block.span.end,
159 };
160 Ok(QualifiedRule {
161 selector: selector_list,
162 block,
163 span,
164 })
165 }
166}
167
168impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for SimpleBlock<'s> {
169 fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
170 let is_sass = input.syntax == Syntax::Sass;
171 let start = if is_sass {
172 if let Some((_, span)) = eat!(input, Indent) {
173 span.end
174 } else {
175 let offset = peek!(input).span.start;
176 return Ok(SimpleBlock {
177 statements: vec![],
178 span: Span {
179 start: offset,
180 end: offset,
181 },
182 });
183 }
184 } else {
185 expect!(input, LBrace).1.start
186 };
187
188 let statements = input.parse_statements(false)?;
189
190 if is_sass {
191 match bump!(input) {
192 TokenWithSpan {
193 token: Token::Dedent(..) | Token::Eof(..),
194 span,
195 } => {
196 let end = span.start;
197 Ok(SimpleBlock {
198 statements,
199 span: Span { start, end },
200 })
201 }
202 TokenWithSpan { span, .. } => Err(Error {
203 kind: ErrorKind::ExpectDedentOrEof,
204 span,
205 }),
206 }
207 } else {
208 let end = expect!(input, RBrace).1.end;
209 Ok(SimpleBlock {
210 statements,
211 span: Span { start, end },
212 })
213 }
214 }
215}
216
217impl<'cmt, 's: 'cmt> Parse<'cmt, 's> for Stylesheet<'s> {
218 fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self> {
219 if input.syntax == Syntax::Sass {
220 eat!(input, Linebreak);
221 }
222
223 let statements = input.parse_statements(true)?;
224 expect!(input, Eof);
225 Ok(Stylesheet {
226 statements,
227 span: Span {
228 start: 0,
229 end: input.source.len(),
230 },
231 })
232 }
233}
234
235impl<'cmt, 's: 'cmt> Parser<'cmt, 's> {
236 fn parse_declaration_value(&mut self) -> PResult<Vec<ComponentValue<'s>>> {
237 let mut values = Vec::with_capacity(3);
238 loop {
239 match &peek!(self).token {
240 Token::RBrace(..)
241 | Token::RParen(..)
242 | Token::Semicolon(..)
243 | Token::Dedent(..)
244 | Token::Linebreak(..)
245 | Token::Exclamation(..)
246 | Token::Eof(..) => break,
247 _ => {
248 let value = self.parse::<ComponentValue>()?;
249 match &value {
250 ComponentValue::SassNestingDeclaration(..)
251 if matches!(self.syntax, Syntax::Scss | Syntax::Sass) =>
252 {
253 values.push(value);
254 break;
255 }
256 _ => values.push(value),
257 }
258 }
259 }
260 }
261 Ok(values)
262 }
263
264 fn parse_statements(&mut self, is_top_level: bool) -> PResult<Vec<Statement<'s>>> {
265 let mut statements = Vec::with_capacity(1);
266 loop {
267 let mut is_block_element = false;
268 let TokenWithSpan { token, span } = peek!(self);
269 match token {
270 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..) => {
271 match self.syntax {
272 Syntax::Css => {
273 if self.state.in_keyframes_at_rule {
274 statements.push(Statement::KeyframeBlock(self.parse()?));
275 is_block_element = true;
276 } else {
277 match self.try_parse(QualifiedRule::parse) {
278 Ok(rule) => {
279 statements.push(Statement::QualifiedRule(rule));
280 is_block_element = true;
281 }
282 Err(error_rule) => match self.parse::<Declaration>() {
283 Ok(decl) => {
284 if is_top_level {
285 self.recoverable_errors.push(Error {
286 kind: ErrorKind::TopLevelDeclaration,
287 span: decl.span.clone(),
288 });
289 }
290 statements.push(Statement::Declaration(decl));
291 }
292 Err(error_decl) => {
293 if is_top_level {
294 return Err(error_rule);
295 } else {
296 return Err(error_decl);
297 }
298 }
299 },
300 }
301 }
302 }
303 Syntax::Scss | Syntax::Sass => {
304 if let Ok(sass_var_decl) =
305 self.try_parse(SassVariableDeclaration::parse)
306 {
307 statements.push(Statement::SassVariableDeclaration(sass_var_decl));
308 } else if self.state.in_keyframes_at_rule {
309 statements.push(Statement::KeyframeBlock(self.parse()?));
310 is_block_element = true;
311 } else {
312 match self.try_parse(QualifiedRule::parse) {
313 Ok(rule) => {
314 statements.push(Statement::QualifiedRule(rule));
315 is_block_element = true;
316 }
317 Err(error_rule) => match self.parse::<Declaration>() {
318 Ok(decl) => {
319 is_block_element = matches!(
320 decl.value.last(),
321 Some(ComponentValue::SassNestingDeclaration(..))
322 );
323 if is_top_level {
324 self.recoverable_errors.push(Error {
325 kind: ErrorKind::TopLevelDeclaration,
326 span: decl.span.clone(),
327 });
328 }
329 statements.push(Statement::Declaration(decl));
330 }
331 Err(error_decl) => {
332 if is_top_level {
333 return Err(error_rule);
334 } else {
335 return Err(error_decl);
336 }
337 }
338 },
339 }
340 }
341 }
342 Syntax::Less => {
343 if let Ok(stmt) = self.try_parse(Parser::parse_less_qualified_rule) {
344 statements.push(stmt);
345 is_block_element = true;
346 } else if let Ok(decl) = self.try_parse(|parser| {
347 if is_top_level {
348 Err(Error {
349 kind: ErrorKind::TryParseError,
350 span: bump!(parser).span,
351 })
352 } else {
353 parser.parse()
354 }
355 }) {
356 statements.push(Statement::Declaration(decl));
357 } else if self.state.in_keyframes_at_rule {
358 statements.push(Statement::KeyframeBlock(self.parse()?));
359 is_block_element = true;
360 } else {
361 let fn_call = self.parse::<Function>()?;
362 is_block_element = fn_call
363 .args
364 .last()
365 .map(ComponentValue::is_less_detached_ruleset)
366 .unwrap_or_default();
367 statements.push(Statement::LessFunctionCall(fn_call));
368 }
369 }
370 }
371 }
372 Token::Dot(..) | Token::Hash(..) if self.syntax == Syntax::Less => {
373 let stmt = if let Ok(stmt) = self.try_parse(Parser::parse_less_qualified_rule) {
374 is_block_element = true;
375 stmt
376 } else if let Ok(mixin_def) = self.try_parse(LessMixinDefinition::parse) {
377 is_block_element = true;
378 Statement::LessMixinDefinition(mixin_def)
379 } else {
380 self.parse().map(Statement::LessMixinCall)?
381 };
382 statements.push(stmt);
383 }
384 Token::Dot(..) | Token::Hash(..) if !self.state.in_keyframes_at_rule => {
385 statements.push(Statement::QualifiedRule(self.parse()?));
386 is_block_element = true;
387 }
388 Token::Ampersand(..)
389 | Token::LBracket(..)
390 | Token::Colon(..)
391 | Token::ColonColon(..)
392 | Token::Asterisk(..)
393 | Token::Bar(..)
394 | Token::NumberSign(..)
395 if !self.state.in_keyframes_at_rule =>
396 {
397 if self.syntax == Syntax::Less {
398 if let Ok(extend_rule) = self.try_parse(LessExtendRule::parse) {
399 statements.push(Statement::LessExtendRule(extend_rule));
400 } else {
401 statements.push(self.parse_less_qualified_rule()?);
402 is_block_element = true;
403 }
404 } else {
405 statements.push(Statement::QualifiedRule(self.parse()?));
406 is_block_element = true;
407 }
408 }
409 Token::AtKeyword(at_keyword) => match self.syntax {
410 Syntax::Css => {
411 let at_rule = self.parse::<AtRule>()?;
412 is_block_element = at_rule.block.is_some();
413 statements.push(Statement::AtRule(at_rule));
414 }
415 Syntax::Scss | Syntax::Sass => {
416 let at_keyword_name = at_keyword.ident.name();
417 match &*at_keyword_name {
418 "if" => {
419 statements.push(Statement::SassIfAtRule(self.parse()?));
420 is_block_element = true;
421 }
422 "else" => {
423 return Err(Error {
424 kind: ErrorKind::UnexpectedSassElseAtRule,
425 span: bump!(self).span,
426 });
427 }
428 _ => {
429 let at_rule = self.parse::<AtRule>()?;
430 is_block_element = at_rule.block.is_some();
431 statements.push(Statement::AtRule(at_rule));
432 }
433 }
434 }
435 Syntax::Less => {
436 if let Ok(less_variable_declaration) =
437 self.try_parse(LessVariableDeclaration::parse)
438 {
439 is_block_element =
440 less_variable_declaration.value.is_less_detached_ruleset();
441 statements.push(Statement::LessVariableDeclaration(
442 less_variable_declaration,
443 ));
444 } else if let Ok(variable_call) = self.try_parse(LessVariableCall::parse) {
445 statements.push(Statement::LessVariableCall(variable_call));
446 } else {
447 let at_rule = self.parse::<AtRule>()?;
448 is_block_element = at_rule.block.is_some();
449 statements.push(Statement::AtRule(at_rule));
450 }
451 }
452 },
453 Token::Percent(..) if matches!(self.syntax, Syntax::Scss | Syntax::Sass) => {
454 statements.push(Statement::QualifiedRule(self.parse()?));
455 is_block_element = true;
456 }
457 Token::DollarVar(..) if matches!(self.syntax, Syntax::Scss | Syntax::Sass) => {
458 statements.push(Statement::SassVariableDeclaration(self.parse()?));
459 }
460 Token::GreaterThan(..) | Token::Plus(..) | Token::Tilde(..) | Token::BarBar(..) => {
461 if self.syntax == Syntax::Less {
462 statements.push(self.parse_less_qualified_rule()?);
463 } else {
464 statements.push(Statement::QualifiedRule(self.parse()?));
465 }
466 is_block_element = true;
467 }
468 Token::DollarLBraceVar(..) if self.syntax == Syntax::Less => {
469 statements.push(self.parse().map(Statement::Declaration)?);
470 }
471 Token::Cdo(..) | Token::Cdc(..) => {
472 bump!(self);
473 continue;
474 }
475 Token::At(..) if matches!(self.syntax, Syntax::Scss | Syntax::Sass) => {
476 let unknown_sass_at_rule = self.parse::<UnknownSassAtRule>()?;
477 is_block_element = unknown_sass_at_rule.block.is_some();
478 statements.push(Statement::UnknownSassAtRule(Box::new(unknown_sass_at_rule)));
479 }
480 Token::Percentage(..)
481 if self.state.in_keyframes_at_rule
482 || self.state.sass_ctx & super::state::SASS_CTX_ALLOW_KEYFRAME_BLOCK
483 != 0
484 || self.state.less_ctx & super::state::LESS_CTX_ALLOW_KEYFRAME_BLOCK
485 != 0 =>
486 {
487 statements.push(Statement::KeyframeBlock(self.parse()?));
488 is_block_element = true;
489 }
490 Token::RBrace(..) | Token::Eof(..) | Token::Dedent(..) => break,
491 Token::Semicolon(..) | Token::Linebreak(..) => {
492 bump!(self);
493 continue;
494 }
495 _ => {
496 return Err(Error {
497 kind: if self.state.in_keyframes_at_rule {
498 ErrorKind::ExpectKeyframeBlock
499 } else {
500 ErrorKind::ExpectRule
501 },
502 span: span.clone(),
503 });
504 }
505 };
506 match &peek!(self).token {
507 Token::RBrace(..) | Token::Eof(..) | Token::Dedent(..) => break,
508 _ => {
509 if self.syntax == Syntax::Sass {
510 if is_block_element {
511 eat!(self, Linebreak);
512 } else if self.options.tolerate_semicolon_in_sass {
513 if let Some((_, span)) = eat!(self, Semicolon) {
514 self.recoverable_errors.push(Error {
515 kind: ErrorKind::UnexpectedSemicolonInSass,
516 span,
517 });
518 }
519 } else {
520 expect!(self, Linebreak);
521 }
522 } else if is_block_element {
523 eat!(self, Semicolon);
524 } else {
525 expect!(self, Semicolon);
526 }
527 }
528 }
529 }
530 Ok(statements)
531 }
532}