1use super::Parser;
2use crate::{
3 Parse, Syntax,
4 ast::*,
5 error::{Error, ErrorKind, PResult},
6 pos::Span,
7 tokenizer::{Token, TokenWithSpan, token},
8 util,
9};
10
11impl<'a> Parse<'a> for AnPlusB {
19 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
20 match input.cursor.peek()? {
21 TokenWithSpan { token: Token::Dimension(..), .. } => {
22 let (token::Dimension { value, unit }, span) = input.cursor.expect_dimension()?;
23 let value_span = Span { start: span.start, end: span.start + value.raw.len() };
24 let unit_name = unit.name();
25 if unit_name.eq_ignore_ascii_case("n") {
26 match &input.cursor.peek()?.token {
27 sign @ Token::Plus(..) | sign @ Token::Minus(..) => {
30 let sign = if let Token::Plus(..) = sign { 1 } else { -1 };
31 input.cursor.bump()?;
32 let (number, number_span) = expect_unsigned_int(input)?;
33 let span = Span { start: span.start, end: number_span.end };
34 Ok(AnPlusB {
35 a: value
36 .try_into()
37 .map_err(|kind| Error { kind, span: value_span })?,
38 b: sign
39 * i32::try_from(number)
40 .map_err(|kind| Error { kind, span: number_span })?,
41 span,
42 })
43 }
44
45 Token::Number(..) => {
48 let (number, number_span) = input.cursor.expect_number()?;
49 let span = Span { start: span.start, end: number_span.end };
50 Ok(AnPlusB {
51 a: value
52 .try_into()
53 .map_err(|kind| Error { kind, span: value_span })?,
54 b: number
55 .try_into()
56 .map_err(|kind| Error { kind, span: number_span })?,
57 span,
58 })
59 }
60
61 _ => Ok(AnPlusB {
64 a: value.try_into().map_err(|kind| Error { kind, span: value_span })?,
65 b: 0,
66 span,
67 }),
68 }
69 } else if unit_name.eq_ignore_ascii_case("n-") {
70 let (number, number_span) = expect_unsigned_int(input)?;
73 let span = Span { start: span.start, end: number_span.end };
74 Ok(AnPlusB {
75 a: value.try_into().map_err(|kind| Error { kind, span: value_span })?,
76 b: -i32::try_from(number)
77 .map_err(|kind| Error { kind, span: number_span })?,
78 span,
79 })
80 } else if let Some(digits) = unit_name.strip_prefix("n-") {
81 if digits.chars().any(|c| !c.is_ascii_digit()) {
84 return Err(Error {
85 kind: ErrorKind::ExpectUnsignedInteger,
86 span: Span { start: span.start + value.raw.len() + 2, end: span.end },
87 });
88 }
89 let b = digits.parse::<i32>().map_err(|_| Error {
90 kind: ErrorKind::ExpectInteger,
91 span: Span { start: span.start + value.raw.len() + 2, end: span.end },
92 })?;
93 Ok(AnPlusB {
94 a: value.try_into().map_err(|kind| Error { kind, span: value_span })?,
95 b: -b,
96 span,
97 })
98 } else {
99 Err(Error { kind: ErrorKind::InvalidAnPlusB, span })
100 }
101 }
102
103 TokenWithSpan { token: Token::Plus(..), .. } => {
104 let plus_span = input.cursor.bump()?.span;
105 let (ident, ident_span) =
106 input.cursor.expect_ident_without_ws_or_comments(false)?;
107 let ident_name = ident.name();
108 if ident_name.eq_ignore_ascii_case("n") {
109 match &input.cursor.peek()?.token {
110 sign @ Token::Plus(..) | sign @ Token::Minus(..) => {
113 let sign = if let Token::Plus(..) = sign { 1 } else { -1 };
114 input.cursor.bump()?;
115 let (number, number_span) = expect_unsigned_int(input)?;
116 let span = Span { start: plus_span.start, end: number_span.end };
117 Ok(AnPlusB {
118 a: 1,
119 b: sign
120 * i32::try_from(number)
121 .map_err(|kind| Error { kind, span: number_span })?,
122 span,
123 })
124 }
125
126 Token::Number(..) => {
129 let (number, number_span) = input.cursor.expect_number()?;
130 let span = Span { start: plus_span.start, end: number_span.end };
131 Ok(AnPlusB {
132 a: 1,
133 b: number
134 .try_into()
135 .map_err(|kind| Error { kind, span: number_span })?,
136 span,
137 })
138 }
139
140 _ => Ok(AnPlusB {
142 a: 1,
143 b: 0,
144 span: Span { start: plus_span.start, end: ident_span.end },
145 }),
146 }
147 } else if ident_name.eq_ignore_ascii_case("n-") {
148 let (number, number_span) = expect_unsigned_int(input)?;
151 let span = Span { start: plus_span.start, end: number_span.end };
152 Ok(AnPlusB {
153 a: 1,
154 b: -i32::try_from(number)
155 .map_err(|kind| Error { kind, span: number_span })?,
156 span,
157 })
158 } else if let Some(digits) = ident_name.strip_prefix("n-") {
159 if digits.chars().any(|c| !c.is_ascii_digit()) {
162 return Err(Error {
163 kind: ErrorKind::ExpectUnsignedInteger,
164 span: Span { start: ident_span.start + 2, end: ident_span.end },
165 });
166 }
167 let b = digits.parse::<i32>().map_err(|_| Error {
168 kind: ErrorKind::ExpectInteger,
169 span: Span { start: ident_span.start + 2, end: ident_span.end },
170 })?;
171 Ok(AnPlusB {
172 a: 1,
173 b: -b,
174 span: Span { start: plus_span.start, end: ident_span.end },
175 })
176 } else {
177 Err(Error {
178 kind: ErrorKind::InvalidAnPlusB,
179 span: Span { start: plus_span.start, end: ident_span.end },
180 })
181 }
182 }
183
184 TokenWithSpan { token: Token::Ident(..), .. } => {
185 let (ident, ident_span) = input.cursor.expect_ident()?;
186 let ident_name = ident.name();
187 if ident_name.eq_ignore_ascii_case("n") {
188 match &input.cursor.peek()?.token {
189 sign @ Token::Plus(..) | sign @ Token::Minus(..) => {
192 let sign = if let Token::Plus(..) = sign { 1 } else { -1 };
193 input.cursor.bump()?;
194 let (number, number_span) = expect_unsigned_int(input)?;
195 let span = Span { start: ident_span.start, end: number_span.end };
196 Ok(AnPlusB {
197 a: 1,
198 b: sign
199 * i32::try_from(number)
200 .map_err(|kind| Error { kind, span: number_span })?,
201 span,
202 })
203 }
204
205 Token::Number(..) => {
208 let (number, number_span) = input.cursor.expect_number()?;
209 let span = Span { start: ident_span.start, end: number_span.end };
210 Ok(AnPlusB {
211 a: 1,
212 b: number
213 .try_into()
214 .map_err(|kind| Error { kind, span: number_span })?,
215 span,
216 })
217 }
218
219 _ => Ok(AnPlusB { a: 1, b: 0, span: ident_span }),
221 }
222 } else if ident_name.eq_ignore_ascii_case("n-") {
223 let (number, number_span) = expect_unsigned_int(input)?;
226 let span = Span { start: ident_span.start, end: number_span.end };
227 Ok(AnPlusB {
228 a: 1,
229 b: -i32::try_from(number)
230 .map_err(|kind| Error { kind, span: number_span })?,
231 span,
232 })
233 } else if let Some(digits) = ident_name.strip_prefix("n-") {
234 if digits.chars().any(|c| !c.is_ascii_digit()) {
237 return Err(Error {
238 kind: ErrorKind::ExpectUnsignedInteger,
239 span: Span { start: ident_span.start + 2, end: ident_span.end },
240 });
241 }
242 let b = digits.parse::<i32>().map_err(|_| Error {
243 kind: ErrorKind::ExpectInteger,
244 span: Span { start: ident_span.start + 2, end: ident_span.end },
245 })?;
246 Ok(AnPlusB { a: 1, b: -b, span: ident_span })
247 } else if ident_name.eq_ignore_ascii_case("-n") {
248 match &input.cursor.peek()?.token {
249 sign @ Token::Plus(..) | sign @ Token::Minus(..) => {
252 let sign = if let Token::Plus(..) = sign { 1 } else { -1 };
253 input.cursor.bump()?;
254 let (number, number_span) = expect_unsigned_int(input)?;
255 let span = Span { start: ident_span.start, end: number_span.end };
256 Ok(AnPlusB {
257 a: -1,
258 b: sign
259 * i32::try_from(number)
260 .map_err(|kind| Error { kind, span: number_span })?,
261 span,
262 })
263 }
264
265 Token::Number(..) => {
268 let (number, number_span) = input.cursor.expect_number()?;
269 let span = Span { start: ident_span.start, end: number_span.end };
270 Ok(AnPlusB {
271 a: -1,
272 b: number
273 .try_into()
274 .map_err(|kind| Error { kind, span: number_span })?,
275 span,
276 })
277 }
278
279 _ => Ok(AnPlusB { a: -1, b: 0, span: ident_span }),
281 }
282 } else if ident_name.eq_ignore_ascii_case("-n-") {
283 let (number, number_span) = expect_unsigned_int(input)?;
286 let span = Span { start: ident_span.start, end: number_span.end };
287 Ok(AnPlusB {
288 a: -1,
289 b: -i32::try_from(number)
290 .map_err(|kind| Error { kind, span: number_span })?,
291 span,
292 })
293 } else if let Some(digits) = ident_name.strip_prefix("-n-") {
294 if digits.chars().any(|c| !c.is_ascii_digit()) {
297 return Err(Error {
298 kind: ErrorKind::ExpectUnsignedInteger,
299 span: Span { start: ident_span.start + 3, end: ident_span.end },
300 });
301 }
302 let b = digits.parse::<i32>().map_err(|_| Error {
303 kind: ErrorKind::ExpectInteger,
304 span: Span { start: ident_span.start + 3, end: ident_span.end },
305 })?;
306 Ok(AnPlusB { a: -1, b: -b, span: ident_span })
307 } else {
308 Err(Error { kind: ErrorKind::InvalidAnPlusB, span: ident_span })
309 }
310 }
311
312 TokenWithSpan { span, .. } => {
313 Err(Error { kind: ErrorKind::InvalidAnPlusB, span: *span })
314 }
315 }
316 }
317}
318
319impl<'a> Parse<'a> for AttributeSelector<'a> {
326 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
327 let start = input.cursor.expect_l_bracket()?.1.start;
328
329 let name = match input.cursor.peek()? {
330 TokenWithSpan {
331 token: Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..),
332 ..
333 } => {
334 let ident = input.parse::<InterpolableIdent>()?;
335 let ident_span = ident.span();
336 if let Some((_, bar_token_span)) = input.cursor.eat_bar()? {
337 let name = input.parse::<InterpolableIdent>()?;
338 let name_span = name.span();
339
340 let start = ident_span.start;
341 let end = name_span.end;
342 WqName {
343 name,
344 prefix: Some(NsPrefix {
345 kind: Some(NsPrefixKind::Ident(ident)),
346 span: Span { start, end: bar_token_span.end },
347 }),
348 span: Span { start, end },
349 }
350 } else {
351 let span = *ident_span;
352 WqName { name: ident, prefix: None, span }
353 }
354 }
355 TokenWithSpan { token: Token::Asterisk(..), .. } => {
356 let asterisk_span = input.cursor.bump()?.span;
357 let bar_token_span = input.cursor.expect_bar()?.1;
358 let name = input.parse::<InterpolableIdent>()?;
359
360 let start = asterisk_span.start;
361 let end = name.span().end;
362 WqName {
363 name,
364 prefix: Some(NsPrefix {
365 kind: Some(NsPrefixKind::Universal(NsPrefixUniversal {
366 span: asterisk_span,
367 })),
368 span: Span { start, end: bar_token_span.end },
369 }),
370 span: Span { start, end },
371 }
372 }
373 TokenWithSpan { token: Token::Bar(..), .. } => {
374 let bar_token_span = input.cursor.bump()?.span;
375 let name = input.parse::<InterpolableIdent>()?;
376
377 let start = bar_token_span.start;
378 let end = name.span().end;
379 WqName {
380 name,
381 prefix: Some(NsPrefix {
382 kind: None,
383 span: Span { start, end: bar_token_span.end },
384 }),
385 span: Span { start, end },
386 }
387 }
388 TokenWithSpan { span, .. } => {
389 return Err(Error { kind: ErrorKind::ExpectWqName, span: *span });
390 }
391 };
392
393 let matcher = match input.cursor.peek()? {
394 TokenWithSpan { token: Token::RBracket(..), .. } => None,
395 TokenWithSpan { token: Token::Equal(..), .. } => Some(AttributeSelectorMatcher {
396 kind: AttributeSelectorMatcherKind::Exact,
397 span: input.cursor.bump()?.span,
398 }),
399 TokenWithSpan { token: Token::TildeEqual(..), .. } => Some(AttributeSelectorMatcher {
400 kind: AttributeSelectorMatcherKind::MatchWord,
401 span: input.cursor.bump()?.span,
402 }),
403 TokenWithSpan { token: Token::BarEqual(..), .. } => Some(AttributeSelectorMatcher {
404 kind: AttributeSelectorMatcherKind::ExactOrPrefixThenHyphen,
405 span: input.cursor.bump()?.span,
406 }),
407 TokenWithSpan { token: Token::CaretEqual(..), .. } => Some(AttributeSelectorMatcher {
408 kind: AttributeSelectorMatcherKind::Prefix,
409 span: input.cursor.bump()?.span,
410 }),
411 TokenWithSpan { token: Token::DollarEqual(..), .. } => Some(AttributeSelectorMatcher {
412 kind: AttributeSelectorMatcherKind::Suffix,
413 span: input.cursor.bump()?.span,
414 }),
415 TokenWithSpan { token: Token::AsteriskEqual(..), .. } => {
416 Some(AttributeSelectorMatcher {
417 kind: AttributeSelectorMatcherKind::Substring,
418 span: input.cursor.bump()?.span,
419 })
420 }
421 TokenWithSpan { span, .. } => {
422 return Err(Error { kind: ErrorKind::ExpectAttributeSelectorMatcher, span: *span });
423 }
424 };
425
426 let value = if matcher.is_some() {
427 match input.cursor.peek()? {
428 TokenWithSpan {
429 token:
430 Token::Ident(..)
431 | Token::HashLBrace(..)
432 | Token::AtLBraceVar(..)
433 | Token::Placeholder(..),
434 ..
435 } => Some(AttributeSelectorValue::Ident(input.parse()?)),
436 TokenWithSpan { token: Token::Str(..) | Token::StrTemplate(..), .. } => {
437 Some(AttributeSelectorValue::Str(input.parse()?))
438 }
439 TokenWithSpan { token: Token::Number(..), .. } => {
443 Some(AttributeSelectorValue::Number(input.parse()?))
444 }
445 TokenWithSpan { token: Token::Dimension(..), .. } => {
446 Some(AttributeSelectorValue::Dimension(input.parse()?))
447 }
448 TokenWithSpan { token: Token::Percentage(..), .. }
449 if input.syntax == Syntax::Less =>
450 {
451 Some(AttributeSelectorValue::Percentage(input.parse()?))
452 }
453 TokenWithSpan { token: Token::Tilde(..), .. } if input.syntax == Syntax::Less => {
454 Some(AttributeSelectorValue::LessEscapedStr(input.parse()?))
455 }
456 TokenWithSpan { token: Token::RBracket(..), span } => {
457 input
458 .recoverable_errors
459 .push(Error { kind: ErrorKind::ExpectAttributeSelectorValue, span: *span });
460 None
461 }
462 TokenWithSpan { span, .. } if input.syntax == Syntax::Css => {
466 let start = span.start;
467 let mut tokens = input.vec();
468 while !matches!(
469 input.cursor.peek()?.token,
470 Token::RBracket(..) | Token::Eof(..)
471 ) {
472 tokens.push(input.cursor.bump()?);
473 }
474 let end = tokens.last().map_or(start, |t| t.span.end);
475 Some(AttributeSelectorValue::TokenSeq(TokenSeq {
476 tokens,
477 span: Span { start, end },
478 }))
479 }
480 token_with_span => {
481 return Err(Error {
482 kind: ErrorKind::ExpectAttributeSelectorValue,
483 span: token_with_span.span,
484 });
485 }
486 }
487 } else {
488 None
489 };
490
491 let modifier = if value.is_some() {
492 match &input.cursor.peek()?.token {
493 Token::Ident(..) | Token::HashLBrace(..) => {
494 let ident = input.parse::<InterpolableIdent>()?;
495 let span = *ident.span();
496 Some(AttributeSelectorModifier { ident, span })
497 }
498 _ => None,
499 }
500 } else {
501 None
502 };
503
504 let end = input.cursor.expect_r_bracket()?.1.end;
505 Ok(AttributeSelector { name, matcher, value, modifier, span: Span { start, end } })
506 }
507}
508
509impl<'a> Parse<'a> for ClassSelector<'a> {
511 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
512 let (_, dot_span) = input.cursor.expect_dot()?;
513 let start = dot_span.start;
514 let end;
515 let placeholder = if input.options.template_placeholder.is_some() {
522 input.cursor.tokenizer.scan_placeholder()
523 } else {
524 None
525 };
526 let name = if let Some(token) = placeholder {
527 let placeholder = token.placeholder(input.source).unwrap();
528 let span = token.span;
529 end = span.end;
530 InterpolableIdent::Placeholder((placeholder, span).into())
531 } else if input.syntax == Syntax::Css {
532 let (ident, ident_span) = input.cursor.expect_ident_without_ws_or_comments(false)?;
533 end = ident_span.end;
534 InterpolableIdent::Literal(input.ident(ident, ident_span))
535 } else {
536 let ident = input.parse::<InterpolableIdent>()?;
537 let ident_span = ident.span();
538 util::assert_no_ws_or_comment(&dot_span, ident_span)?;
539 end = ident_span.end;
540 ident
541 };
542
543 Ok(ClassSelector { name, span: Span { start, end } })
544 }
545}
546
547impl<'a> Parse<'a> for ComplexSelector<'a> {
549 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
550 let mut children = input.vec_with_capacity(3);
551
552 let (span, first, mut is_previous_combinator) = if let Token::GreaterThan(..)
553 | Token::Plus(..)
554 | Token::Tilde(..)
555 | Token::BarBar(..) =
556 input.cursor.peek()?.token
557 {
558 let end = input.cursor.tokenizer.current_offset();
559 if let Some(combinator) = input.parse_combinator(end)? {
560 (combinator.span, ComplexSelectorChild::Combinator(combinator), true)
561 } else {
562 return Err(Error {
563 kind: ErrorKind::ExpectSimpleSelector,
564 span: input.cursor.bump()?.span,
565 });
566 }
567 } else {
568 let compound_selector = input.parse::<CompoundSelector>()?;
569 (
570 compound_selector.span,
571 ComplexSelectorChild::CompoundSelector(compound_selector),
572 false,
573 )
574 };
575 let Span { start, mut end } = span;
576
577 children.push(first);
578 let is_less = input.syntax == Syntax::Less;
579 while !matches!(
580 input.cursor.peek()?.token,
581 Token::LBrace(..) | Token::Indent(..) | Token::Linebreak(..)
582 ) {
583 if is_previous_combinator {
584 if matches!(input.syntax, Syntax::Scss | Syntax::Sass) {
589 if matches!(
590 input.cursor.peek()?.token,
591 Token::GreaterThan(..)
592 | Token::Plus(..)
593 | Token::Tilde(..)
594 | Token::BarBar(..)
595 ) && let Some(combinator) = input.parse_combinator(end)?
596 {
597 end = combinator.span.end;
598 children.push(ComplexSelectorChild::Combinator(combinator));
599 continue;
600 } else if matches!(
601 input.cursor.peek()?.token,
602 Token::RParen(..) | Token::Comma(..) | Token::RBrace(..) | Token::Eof(..)
603 ) {
604 break;
605 }
606 }
607 let compound_selector = input.parse::<CompoundSelector>()?;
608 end = compound_selector.span.end;
609 children.push(ComplexSelectorChild::CompoundSelector(compound_selector));
610 } else if let Some(combinator) = input.parse_combinator(end)? {
611 if is_less
612 && combinator.kind == CombinatorKind::Descendant
613 && input.cursor.peek()?.is_ident_raw(input.source, "when")
614 {
615 break;
616 }
617 children.push(ComplexSelectorChild::Combinator(combinator));
618 } else {
619 break;
620 }
621 is_previous_combinator = !is_previous_combinator;
622 }
623
624 Ok(ComplexSelector { children, span: Span { start, end } })
625 }
626}
627
628impl<'a> Parse<'a> for CompoundSelector<'a> {
631 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
632 let first = input.parse::<SimpleSelector>()?;
633 let first_span = first.span();
634 let start = first_span.start;
635 let mut end = first_span.end;
636
637 let mut children = input.vec_with_capacity(2);
638 children.push(first);
639 loop {
640 use token::*;
641 match input.cursor.peek()? {
642 TokenWithSpan {
643 token:
644 Token::Dot(..)
645 | Token::Hash(..)
646 | Token::NumberSign(..)
647 | Token::LBracket(..)
648 | Token::Colon(..)
649 | Token::ColonColon(..)
650 | Token::Ident(..)
651 | Token::Asterisk(..)
652 | Token::HashLBrace(..)
653 | Token::Bar(..)
654 | Token::Ampersand(..)
655 | Token::AtLBraceVar(..),
656 span,
657 } if !util::has_ws(input.source, end, span.start) => {
658 let child = input.parse::<SimpleSelector>()?;
659 end = child.span().end;
660 children.push(child);
661 }
662 TokenWithSpan { token: Token::Percent(..), span }
663 if matches!(input.syntax, Syntax::Scss | Syntax::Sass)
664 && !util::has_ws(input.source, end, span.start) =>
665 {
666 let child = input.parse::<SimpleSelector>()?;
667 end = child.span().end;
668 children.push(child);
669 }
670 TokenWithSpan { token: Token::Placeholder(..), span }
671 if !util::has_ws(input.source, end, span.start) =>
672 {
673 let child = input.parse::<SimpleSelector>()?;
674 end = child.span().end;
675 children.push(child);
676 }
677 _ => break,
678 }
679 }
680
681 Ok(CompoundSelector { children, span: Span { start, end } })
682 }
683}
684
685impl<'a> Parse<'a> for CompoundSelectorList<'a> {
687 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
688 let first = input.parse::<CompoundSelector>()?;
689 let mut span = first.span;
690
691 let mut selectors = input.vec1(first);
692 let mut comma_spans = input.vec();
693 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
694 comma_spans.push(comma_span);
695 input.eat_sass_line_continuation()?;
696 selectors.push(input.parse()?);
697 }
698
699 span.end = unsafe {
701 let index = selectors.len() - 1;
702 selectors.get_unchecked(index).span().end
703 };
704 Ok(CompoundSelectorList { selectors, comma_spans, span })
705 }
706}
707
708impl<'a> Parse<'a> for IdSelector<'a> {
710 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
711 match input.cursor.bump()? {
712 token @ TokenWithSpan { token: Token::Hash(..), span } => {
713 let token = token.hash(input.source).unwrap();
714 let first_span = Span { start: span.start + 1, end: span.end };
715 let raw = token.raw;
716 if raw.starts_with(|c: char| c.is_ascii_digit())
717 || matches!(raw.as_bytes(), [b'-'] | [b'-', b'0'..=b'9', ..])
718 {
719 input
720 .recoverable_errors
721 .push(Error { kind: ErrorKind::InvalidIdSelectorName, span });
722 }
723 let value =
724 if token.escaped { util::handle_escape_in(raw, input.allocator) } else { raw };
725 let first = Ident { name: value, raw: token.raw, span: first_span };
726 let name = match input.cursor.peek()? {
727 TokenWithSpan { token: Token::HashLBrace(..), span }
728 if matches!(input.syntax, Syntax::Scss | Syntax::Sass)
729 && first.span.end == span.start =>
730 {
731 match input.parse()? {
732 InterpolableIdent::SassInterpolated(mut interpolation) => {
733 interpolation.elements.insert(
734 0,
735 SassInterpolatedIdentElement::Static(
736 InterpolableIdentStaticPart {
737 value: first.name,
738 raw: first.raw,
739 span: first.span,
740 },
741 ),
742 );
743 InterpolableIdent::SassInterpolated(interpolation)
744 }
745 _ => unreachable!(),
746 }
747 }
748 _ => InterpolableIdent::Literal(first),
749 };
750 let span = Span { start: span.start, end: name.span().end };
751 Ok(IdSelector { name, span })
752 }
753 TokenWithSpan { token: Token::NumberSign(..), span } => {
754 let name = input.parse::<InterpolableIdent>()?;
755 let span = Span { start: span.start, end: name.span().end };
756 Ok(IdSelector { name, span })
757 }
758 TokenWithSpan { span, .. } => Err(Error { kind: ErrorKind::ExpectIdSelector, span }),
759 }
760 }
761}
762
763impl<'a> Parse<'a> for LanguageRange<'a> {
765 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
766 match &input.cursor.peek()?.token {
767 Token::Str(..) | Token::StrTemplate(..) => input.parse().map(LanguageRange::Str),
768 _ => input.parse().map(LanguageRange::Ident),
769 }
770 }
771}
772
773impl<'a> Parse<'a> for LanguageRangeList<'a> {
775 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
776 let first = input.parse::<LanguageRange>()?;
777 let mut span = *first.span();
778
779 let mut ranges = input.vec1(first);
780 let mut comma_spans = input.vec();
781 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
782 comma_spans.push(comma_span);
783 ranges.push(input.parse()?);
784 }
785 debug_assert_eq!(comma_spans.len() + 1, ranges.len());
786
787 if let Some(end) = ranges.last() {
788 span.end = end.span().end;
789 }
790 Ok(LanguageRangeList { ranges, comma_spans, span })
791 }
792}
793
794impl<'a> Parse<'a> for NestingSelector<'a> {
799 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
800 let (_, mut span) = input.cursor.expect_ampersand()?;
801 let suffix = match input.syntax {
802 Syntax::Css => {
803 if let Some((ident, ident_span)) = input.cursor.tokenizer.scan_ident_template()? {
804 span.end = ident_span.end;
805 Some(InterpolableIdent::Literal(input.ident(ident, ident_span)))
806 } else {
807 None
808 }
809 }
810 Syntax::Scss | Syntax::Sass => {
811 let start = span.end;
812 let elements = input.parse_sass_interpolated_ident_rest(&mut span.end)?;
813 if elements.is_empty() {
814 None
815 } else {
816 Some(InterpolableIdent::SassInterpolated(SassInterpolatedIdent {
817 elements,
818 span: Span { start, end: span.end },
819 }))
820 }
821 }
822 Syntax::Less => {
823 let start = span.end;
824 let elements = input.parse_less_interpolated_ident_rest(&mut span.end)?;
825 if elements.is_empty() {
826 None
827 } else {
828 Some(InterpolableIdent::LessInterpolated(LessInterpolatedIdent {
829 elements,
830 span: Span { start, end: span.end },
831 }))
832 }
833 }
834 };
835 Ok(NestingSelector { suffix, span })
836 }
837}
838
839impl<'a> Parse<'a> for Nth<'a> {
843 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
844 let index = input.parse::<NthIndex>()?;
845 let mut span = *index.span();
846 let matcher = if input.cursor.peek()?.is_ident_name_eq_ignore_ascii_case(input.source, "of")
847 {
848 let matcher = input.parse::<NthMatcher>()?;
849 span.end = matcher.span.end;
850 Some(matcher)
851 } else {
852 None
853 };
854
855 Ok(Nth { index, matcher, span })
856 }
857}
858
859impl<'a> Parse<'a> for NthIndex<'a> {
861 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
862 let peek = input.cursor.peek()?;
863 if peek.ident(input.source).is_some() {
864 if peek.is_ident_name_eq_ignore_ascii_case(input.source, "odd") {
865 input.parse().map(NthIndex::Odd)
866 } else if peek.is_ident_name_eq_ignore_ascii_case(input.source, "even") {
867 input.parse().map(NthIndex::Even)
868 } else {
869 input.parse().map(NthIndex::AnPlusB)
870 }
871 } else if matches!(peek.token, Token::Number(..)) {
872 let number = input.parse::<Number>()?;
873 if number.value.fract() == 0.0 {
874 Ok(NthIndex::Integer(number))
875 } else {
876 Err(Error { kind: ErrorKind::ExpectInteger, span: number.span })
877 }
878 } else {
879 input.parse().map(NthIndex::AnPlusB)
880 }
881 }
882}
883
884impl<'a> Parse<'a> for NthMatcher<'a> {
886 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
887 let (ident, mut span) = input.cursor.expect_ident()?;
888 if !ident.name().eq_ignore_ascii_case("of") {
889 return Err(Error { kind: ErrorKind::ExpectNthOf, span });
890 }
891
892 let selector = if matches!(&input.cursor.peek()?.token, Token::RParen(..)) {
893 None
894 } else {
895 let selector = input.parse::<SelectorList>()?;
896 span.end = selector.span.end;
897 Some(selector)
898 };
899
900 Ok(NthMatcher { selector, span })
901 }
902}
903
904impl<'a> Parse<'a> for PseudoClassSelector<'a> {
909 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
910 let (_, colon_span) = input.cursor.expect_colon()?;
911 let name = input.parse::<InterpolableIdent>()?;
912 let name_span = name.span();
913 util::assert_no_ws(input.source, &colon_span, name_span)?;
914
915 let mut end = name_span.end;
916
917 let arg = match input.cursor.peek()? {
918 TokenWithSpan { token: Token::LParen(..), span: l_paren } if l_paren.start == end => {
919 let l_paren = *l_paren;
920 input.cursor.bump()?;
921 let kind = match &name {
922 InterpolableIdent::Literal(Ident { name, .. })
923 if name.eq_ignore_ascii_case("nth-child")
924 || name.eq_ignore_ascii_case("nth-last-child") =>
925 {
926 if input.syntax == Syntax::Css {
927 input.parse().map(PseudoClassSelectorArgKind::Nth)?
928 } else if let Ok(nth) = input.try_parse(Nth::parse) {
929 PseudoClassSelectorArgKind::Nth(nth)
930 } else {
931 input
932 .parse_tokens_in_parens()
933 .map(PseudoClassSelectorArgKind::TokenSeq)?
934 }
935 }
936 InterpolableIdent::Literal(Ident { name, .. })
937 if name.eq_ignore_ascii_case("nth-of-type")
938 || name.eq_ignore_ascii_case("nth-last-of-type")
939 || name.eq_ignore_ascii_case("nth-col")
940 || name.eq_ignore_ascii_case("nth-last-col") =>
941 'pseudo_arg: {
942 let nth = if input.syntax == Syntax::Css {
943 input.parse()?
944 } else if let Ok(nth) = input.try_parse(Nth::parse) {
945 nth
946 } else {
947 break 'pseudo_arg input
948 .parse_tokens_in_parens()
949 .map(PseudoClassSelectorArgKind::TokenSeq)?;
950 };
951 if let Some(NthMatcher { span, .. }) = &nth.matcher {
952 input
953 .recoverable_errors
954 .push(Error { kind: ErrorKind::UnexpectedNthMatcher, span: *span });
955 }
956 PseudoClassSelectorArgKind::Nth(nth)
957 }
958 InterpolableIdent::Literal(Ident { name, .. })
959 if name.eq_ignore_ascii_case("not")
960 || name.eq_ignore_ascii_case("is")
961 || name.eq_ignore_ascii_case("where")
962 || name.eq_ignore_ascii_case("matches")
963 || name.eq_ignore_ascii_case("global") =>
964 {
965 input.parse().map(PseudoClassSelectorArgKind::SelectorList)?
966 }
967 InterpolableIdent::Literal(Ident { name, .. })
968 if name.eq_ignore_ascii_case("has") =>
969 {
970 input.parse().map(PseudoClassSelectorArgKind::RelativeSelectorList)?
971 }
972 InterpolableIdent::Literal(Ident { name, .. })
973 if name.eq_ignore_ascii_case("dir") =>
974 {
975 input.parse().map(PseudoClassSelectorArgKind::Ident)?
976 }
977 InterpolableIdent::Literal(Ident { name, .. })
978 if name.eq_ignore_ascii_case("lang") =>
979 {
980 input.parse().map(PseudoClassSelectorArgKind::LanguageRangeList)?
981 }
982 InterpolableIdent::Literal(Ident { name, .. })
983 if name.eq_ignore_ascii_case("-moz-any")
984 || name.eq_ignore_ascii_case("-webkit-any")
985 || name.eq_ignore_ascii_case("any") =>
986 {
987 input.parse().map(PseudoClassSelectorArgKind::SelectorList)?
990 }
991 InterpolableIdent::Literal(Ident { name, .. })
992 if name.eq_ignore_ascii_case("current")
993 || name.eq_ignore_ascii_case("past")
994 || name.eq_ignore_ascii_case("future") =>
995 {
996 input.parse().map(PseudoClassSelectorArgKind::CompoundSelectorList)?
997 }
998 InterpolableIdent::Literal(Ident { name, .. })
999 if name.eq_ignore_ascii_case("host")
1000 || name.eq_ignore_ascii_case("host-context") =>
1001 {
1002 input.parse().map(PseudoClassSelectorArgKind::CompoundSelector)?
1003 }
1004 InterpolableIdent::Literal(Ident { name, .. })
1005 if input.syntax == Syntax::Less && *name == "extend" =>
1006 {
1007 input.parse().map(PseudoClassSelectorArgKind::LessExtendList)?
1008 }
1009 _ => {
1010 input.parse_tokens_in_parens().map(PseudoClassSelectorArgKind::TokenSeq)?
1011 }
1012 };
1013
1014 let r_paren = input.cursor.expect_r_paren()?.1;
1015 end = r_paren.end;
1016 let span = Span { start: l_paren.start, end: r_paren.end };
1017 Some(PseudoClassSelectorArg { kind, l_paren, r_paren, span })
1018 }
1019 _ => None,
1020 };
1021
1022 let span = Span { start: colon_span.start, end };
1023 Ok(PseudoClassSelector { name, arg, span })
1024 }
1025}
1026
1027impl<'a> Parse<'a> for PseudoElementSelector<'a> {
1032 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1033 let (_, colon_colon_span) = input.cursor.expect_colon_colon()?;
1034 let mut end;
1035 let name = if input.syntax == Syntax::Css {
1036 let (ident, ident_span) = input.cursor.expect_ident()?;
1037 end = ident_span.end;
1038 util::assert_no_ws(input.source, &colon_colon_span, &ident_span)?;
1039 InterpolableIdent::Literal(input.ident(ident, ident_span))
1040 } else {
1041 let name = input.parse::<InterpolableIdent>()?;
1042 let name_span = name.span();
1043 end = name_span.end;
1044 util::assert_no_ws(input.source, &colon_colon_span, name_span)?;
1045 name
1046 };
1047
1048 let arg = match input.cursor.peek()? {
1049 TokenWithSpan { token: Token::LParen(..), span: l_paren } if l_paren.start == end => {
1050 let l_paren = *l_paren;
1051 input.cursor.bump()?;
1052 let kind = match &name {
1053 InterpolableIdent::Literal(Ident { name, .. })
1054 if name.eq_ignore_ascii_case("part") =>
1055 {
1056 let first = input.parse::<InterpolableIdent>()?;
1059 if matches!(
1060 input.cursor.peek()?.token,
1061 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..)
1062 ) {
1063 let mut span = *first.span();
1064 let mut idents = input.vec_with_capacity(2);
1065 idents.push(first);
1066 while matches!(
1067 input.cursor.peek()?.token,
1068 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..)
1069 ) {
1070 let ident = input.parse::<InterpolableIdent>()?;
1071 span.end = ident.span().end;
1072 idents.push(ident);
1073 }
1074 PseudoElementSelectorArgKind::IdentList(IdentList { idents, span })
1075 } else {
1076 PseudoElementSelectorArgKind::Ident(first)
1077 }
1078 }
1079 InterpolableIdent::Literal(Ident { name, .. })
1080 if name.eq_ignore_ascii_case("cue")
1081 || name.eq_ignore_ascii_case("cue-region") =>
1082 {
1083 input.parse().map(PseudoElementSelectorArgKind::CompoundSelector)?
1084 }
1085 InterpolableIdent::Literal(Ident { name, .. })
1086 if name.eq_ignore_ascii_case("slotted") =>
1087 {
1088 input.parse().map(PseudoElementSelectorArgKind::CompoundSelectorList)?
1091 }
1092 _ => input
1093 .parse_tokens_in_parens()
1094 .map(PseudoElementSelectorArgKind::TokenSeq)?,
1095 };
1096
1097 let r_paren = input.cursor.expect_r_paren()?.1;
1098 end = r_paren.end;
1099 let span = Span { start: l_paren.start, end: r_paren.end };
1100 Some(PseudoElementSelectorArg { kind, l_paren, r_paren, span })
1101 }
1102 _ => None,
1103 };
1104
1105 let span = Span { start: colon_colon_span.start, end };
1106 Ok(PseudoElementSelector { name, arg, span })
1107 }
1108}
1109
1110impl<'a> Parse<'a> for RelativeSelector<'a> {
1112 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1113 let pos = input.cursor.tokenizer.current_offset();
1114 let combinator = match input.parse_combinator(pos)? {
1115 Some(Combinator { kind: CombinatorKind::Descendant, .. }) => None,
1116 combinator => combinator,
1117 };
1118 let complex_selector = input.parse::<ComplexSelector>()?;
1119 let mut span = complex_selector.span;
1120 if let Some(combinator) = &combinator {
1121 span.start = combinator.span.start;
1122 }
1123 Ok(RelativeSelector { combinator, complex_selector, span })
1124 }
1125}
1126
1127impl<'a> Parse<'a> for RelativeSelectorList<'a> {
1129 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1130 let first = input.parse::<RelativeSelector>()?;
1131 let mut span = first.span;
1132
1133 let mut selectors = input.vec1(first);
1134 let mut comma_spans = input.vec();
1135 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1136 comma_spans.push(comma_span);
1137 selectors.push(input.parse()?);
1138 }
1139
1140 span.end = unsafe {
1142 let index = selectors.len() - 1;
1143 selectors.get_unchecked(index).span().end
1144 };
1145 Ok(RelativeSelectorList { selectors, comma_spans, span })
1146 }
1147}
1148
1149impl<'a> Parse<'a> for SelectorList<'a> {
1153 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1154 let first = input.parse::<ComplexSelector>()?;
1155 let mut span = first.span;
1156
1157 let mut selectors = input.vec_with_capacity(2);
1158 selectors.push(first);
1159 let mut comma_spans = input.vec();
1160
1161 let is_css = input.syntax == Syntax::Css;
1162 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1163 span.end = comma_span.end;
1164 comma_spans.push(comma_span);
1165 if input.syntax == Syntax::Scss {
1168 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1169 span.end = comma_span.end;
1170 comma_spans.push(comma_span);
1171 }
1172 }
1173 if input.syntax == Syntax::Sass
1177 && matches!(input.cursor.peek()?.token, Token::Indent(..))
1178 {
1179 input.eat_sass_line_continuation()?;
1180 } else if !is_css
1181 && matches!(
1182 input.cursor.peek()?.token,
1183 Token::LBrace(..) | Token::Indent(..) | Token::Linebreak(..)
1184 )
1185 {
1186 break;
1187 }
1188
1189 let selector = input.parse::<ComplexSelector>()?;
1190 span.end = selector.span.end;
1191 selectors.push(selector);
1192 }
1193
1194 debug_assert!(if is_css {
1197 selectors.len() == comma_spans.len() + 1
1198 } else {
1199 selectors.len() <= comma_spans.len() + 1
1200 });
1201
1202 Ok(SelectorList { selectors, comma_spans, span })
1203 }
1204}
1205
1206impl<'a> Parse<'a> for SimpleSelector<'a> {
1212 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1213 match input.cursor.peek()? {
1214 TokenWithSpan { token: Token::Dot(..), .. } => input.parse().map(SimpleSelector::Class),
1215 TokenWithSpan { token: Token::Hash(..) | Token::NumberSign(..), .. } => {
1216 input.parse().map(SimpleSelector::Id)
1217 }
1218 TokenWithSpan { token: Token::LBracket(..), .. } => {
1219 input.parse().map(SimpleSelector::Attribute)
1220 }
1221 TokenWithSpan { token: Token::Colon(..), .. } => {
1222 input.parse().map(SimpleSelector::PseudoClass)
1223 }
1224 TokenWithSpan { token: Token::ColonColon(..), .. } => {
1225 input.parse().map(SimpleSelector::PseudoElement)
1226 }
1227 TokenWithSpan {
1228 token:
1229 Token::Ident(..)
1230 | Token::Asterisk(..)
1231 | Token::HashLBrace(..)
1232 | Token::Bar(..)
1233 | Token::AtLBraceVar(..),
1234 ..
1235 } => input.parse().map(SimpleSelector::Type),
1236 TokenWithSpan { token: Token::Ampersand(..), .. } => {
1237 input.parse().map(SimpleSelector::Nesting)
1238 }
1239 TokenWithSpan { token: Token::Percent(..), .. }
1244 if matches!(input.syntax, Syntax::Scss | Syntax::Sass | Syntax::Css) =>
1245 {
1246 input.parse().map(SimpleSelector::SassPlaceholder)
1247 }
1248 TokenWithSpan { token: Token::Placeholder(..), .. } => {
1249 let name = input.parse::<InterpolableIdent>()?;
1250 let span = *name.span();
1251 Ok(SimpleSelector::Type(TypeSelector::TagName(TagNameSelector {
1252 name: WqName { name, prefix: None, span },
1253 span,
1254 })))
1255 }
1256 token_with_span => {
1257 Err(Error { kind: ErrorKind::ExpectSimpleSelector, span: token_with_span.span })
1258 }
1259 }
1260 }
1261}
1262
1263impl<'a> Parse<'a> for TypeSelector<'a> {
1267 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1268 enum IdentOrAsterisk<'a> {
1269 Ident(InterpolableIdent<'a>),
1270 Asterisk(Span),
1271 }
1272
1273 let ident_or_asterisk = match &input.cursor.peek()?.token {
1274 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..) => {
1275 input.parse().map(IdentOrAsterisk::Ident).map(Some)?
1276 }
1277 Token::Asterisk(..) => Some(IdentOrAsterisk::Asterisk(input.cursor.bump()?.span)),
1278 Token::Bar(..) => None,
1279 _ => unreachable!(),
1280 };
1281
1282 match input.cursor.peek()? {
1283 TokenWithSpan { token: Token::Bar(..), span }
1284 if ident_or_asterisk
1285 .as_ref()
1286 .map(|t| match t {
1287 IdentOrAsterisk::Ident(ident) => {
1288 !util::has_ws(input.source, ident.span().end, span.start)
1289 }
1290 IdentOrAsterisk::Asterisk(asterisk_span) => {
1291 !util::has_ws(input.source, asterisk_span.end, span.start)
1292 }
1293 })
1294 .unwrap_or(true) =>
1295 {
1296 let bar_token_span = input.cursor.bump()?.span;
1297
1298 let prefix = match ident_or_asterisk {
1299 Some(IdentOrAsterisk::Ident(ident)) => {
1300 let mut span = *ident.span();
1301 span.end = bar_token_span.end;
1302 NsPrefix { kind: Some(NsPrefixKind::Ident(ident)), span }
1303 }
1304 Some(IdentOrAsterisk::Asterisk(asterisk_span)) => {
1305 let mut span = asterisk_span;
1306 span.end = bar_token_span.end;
1307 NsPrefix {
1308 kind: Some(NsPrefixKind::Universal(NsPrefixUniversal {
1309 span: asterisk_span,
1310 })),
1311 span,
1312 }
1313 }
1314 None => NsPrefix { kind: None, span: bar_token_span },
1315 };
1316
1317 match input.cursor.peek()? {
1318 TokenWithSpan { token: Token::Ident(..) | Token::HashLBrace(..), .. } => {
1319 let name = input.parse::<InterpolableIdent>()?;
1320 let name_span = name.span();
1321 util::assert_no_ws(input.source, &prefix.span, name_span)?;
1322 let span = Span { start: prefix.span.start, end: name_span.end };
1323 Ok(TypeSelector::TagName(TagNameSelector {
1324 name: WqName { name, prefix: Some(prefix), span },
1325 span,
1326 }))
1327 }
1328 TokenWithSpan { token: Token::Asterisk(..), .. } => {
1329 let asterisk_span = input.cursor.bump()?.span;
1330 util::assert_no_ws(input.source, &prefix.span, &asterisk_span)?;
1331 let span = Span { start: prefix.span.start, end: asterisk_span.end };
1332 Ok(TypeSelector::Universal(UniversalSelector {
1333 prefix: Some(prefix),
1334 span,
1335 }))
1336 }
1337 TokenWithSpan { span, .. } => {
1338 Err(Error { kind: ErrorKind::ExpectTypeSelector, span: *span })
1339 }
1340 }
1341 }
1342
1343 _ => match ident_or_asterisk {
1344 Some(IdentOrAsterisk::Ident(ident)) => {
1345 let span = *ident.span();
1346 Ok(TypeSelector::TagName(TagNameSelector {
1347 name: WqName { name: ident, prefix: None, span },
1348 span,
1349 }))
1350 }
1351 Some(IdentOrAsterisk::Asterisk(span)) => {
1352 Ok(TypeSelector::Universal(UniversalSelector { prefix: None, span }))
1353 }
1354 None => unreachable!(),
1355 },
1356 }
1357 }
1358}
1359
1360impl<'a> Parser<'a> {
1361 fn parse_combinator(&mut self, pos: usize) -> PResult<Option<Combinator>> {
1365 match self.cursor.peek()? {
1366 TokenWithSpan {
1367 token:
1368 Token::Ident(..)
1369 | Token::Dot(..)
1370 | Token::Hash(..)
1371 | Token::Colon(..)
1372 | Token::ColonColon(..)
1373 | Token::LBracket(..)
1374 | Token::Asterisk(..)
1375 | Token::Ampersand(..)
1376 | Token::Bar(..) | Token::AtLBraceVar(..)
1378 | Token::NumberSign(..)
1379 | Token::HashLBrace(..)
1380 | Token::Percent(..) | Token::Placeholder(..), span,
1383 } if pos < span.start => Ok(Some(Combinator {
1384 kind: CombinatorKind::Descendant,
1385 span: Span {
1386 start: pos,
1387 end: span.start,
1388 },
1389 })),
1390 TokenWithSpan {
1391 token: Token::GreaterThan(..),
1392 ..
1393 } => Ok(Some(Combinator {
1394 kind: CombinatorKind::Child,
1395 span: self.cursor.bump()?.span,
1396 })),
1397 TokenWithSpan {
1398 token: Token::Plus(..),
1399 ..
1400 } => Ok(Some(Combinator {
1401 kind: CombinatorKind::NextSibling,
1402 span: self.cursor.bump()?.span,
1403 })),
1404 TokenWithSpan {
1405 token: Token::Tilde(..),
1406 ..
1407 } => Ok(Some(Combinator {
1408 kind: CombinatorKind::LaterSibling,
1409 span: self.cursor.bump()?.span,
1410 })),
1411 TokenWithSpan {
1412 token: Token::BarBar(..),
1413 ..
1414 } => Ok(Some(Combinator {
1415 kind: CombinatorKind::Column,
1416 span: self.cursor.bump()?.span,
1417 })),
1418 TokenWithSpan { token: Token::Solidus(..), .. }
1422 if !matches!(self.syntax, Syntax::Scss | Syntax::Sass) =>
1423 {
1424 let deep = self.try_parse(|p| {
1425 let start = p.cursor.bump()?.span; let ident_end = match p.cursor.peek()? {
1427 TokenWithSpan { token: Token::Ident(..), span }
1428 if span.start == start.end =>
1429 {
1430 p.cursor.bump()?.span.end
1431 }
1432 TokenWithSpan { span, .. } => {
1433 return Err(Error {
1434 kind: ErrorKind::TryParseError,
1435 span: *span,
1436 });
1437 }
1438 };
1439 match p.cursor.peek()? {
1440 TokenWithSpan { token: Token::Solidus(..), span }
1441 if span.start == ident_end =>
1442 {
1443 let end = p.cursor.bump()?.span.end;
1444 Ok(Span { start: start.start, end })
1445 }
1446 TokenWithSpan { span, .. } => Err(Error {
1447 kind: ErrorKind::TryParseError,
1448 span: *span,
1449 }),
1450 }
1451 });
1452 match deep {
1453 Ok(span) => Ok(Some(Combinator { kind: CombinatorKind::Deep, span })),
1454 Err(_) => Ok(None),
1455 }
1456 }
1457 TokenWithSpan {
1460 token: Token::Unknown(..),
1461 span,
1462 } if !matches!(self.syntax, Syntax::Scss | Syntax::Sass)
1463 && self.source.as_bytes().get(span.start) == Some(&b'^') =>
1464 {
1465 let start = self.cursor.bump()?.span.start;
1466 if matches!(&self.cursor.peek()?.token, Token::Unknown(..))
1467 && self.cursor.peek()?.span.start == start + 1
1468 && self.source.as_bytes().get(start + 1) == Some(&b'^')
1469 {
1470 let end = self.cursor.bump()?.span.end;
1471 Ok(Some(Combinator {
1472 kind: CombinatorKind::ShadowDescendant,
1473 span: Span { start, end },
1474 }))
1475 } else {
1476 Ok(Some(Combinator {
1477 kind: CombinatorKind::ShadowChild,
1478 span: Span { start, end: start + 1 },
1479 }))
1480 }
1481 }
1482 _ => Ok(None),
1483 }
1484 }
1485}
1486
1487fn expect_unsigned_int<'a>(input: &mut Parser<'a>) -> PResult<(token::Number<'a>, Span)> {
1488 let (number, span) = input.cursor.expect_number()?;
1489 if number.raw.chars().any(|c| !c.is_ascii_digit()) {
1490 Err(Error { kind: ErrorKind::ExpectUnsignedInteger, span })
1491 } else {
1492 Ok((number, span))
1493 }
1494}