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