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