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 input.parse().map(PseudoElementSelectorArgKind::Ident)?
1057 }
1058 InterpolableIdent::Literal(Ident { name, .. })
1059 if name.eq_ignore_ascii_case("cue")
1060 || name.eq_ignore_ascii_case("cue-region") =>
1061 {
1062 input.parse().map(PseudoElementSelectorArgKind::CompoundSelector)?
1063 }
1064 InterpolableIdent::Literal(Ident { name, .. })
1065 if name.eq_ignore_ascii_case("slotted") =>
1066 {
1067 input.parse().map(PseudoElementSelectorArgKind::CompoundSelectorList)?
1070 }
1071 _ => input
1072 .parse_tokens_in_parens()
1073 .map(PseudoElementSelectorArgKind::TokenSeq)?,
1074 };
1075
1076 let r_paren = input.cursor.expect_r_paren()?.1;
1077 end = r_paren.end;
1078 let span = Span { start: l_paren.start, end: r_paren.end };
1079 Some(PseudoElementSelectorArg { kind, l_paren, r_paren, span })
1080 }
1081 _ => None,
1082 };
1083
1084 let span = Span { start: colon_colon_span.start, end };
1085 Ok(PseudoElementSelector { name, arg, span })
1086 }
1087}
1088
1089impl<'a> Parse<'a> for RelativeSelector<'a> {
1091 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1092 let pos = input.cursor.tokenizer.current_offset();
1093 let combinator = match input.parse_combinator(pos)? {
1094 Some(Combinator { kind: CombinatorKind::Descendant, .. }) => None,
1095 combinator => combinator,
1096 };
1097 let complex_selector = input.parse::<ComplexSelector>()?;
1098 let mut span = complex_selector.span;
1099 if let Some(combinator) = &combinator {
1100 span.start = combinator.span.start;
1101 }
1102 Ok(RelativeSelector { combinator, complex_selector, span })
1103 }
1104}
1105
1106impl<'a> Parse<'a> for RelativeSelectorList<'a> {
1108 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1109 let first = input.parse::<RelativeSelector>()?;
1110 let mut span = first.span;
1111
1112 let mut selectors = input.vec1(first);
1113 let mut comma_spans = input.vec();
1114 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1115 comma_spans.push(comma_span);
1116 selectors.push(input.parse()?);
1117 }
1118
1119 span.end = unsafe {
1121 let index = selectors.len() - 1;
1122 selectors.get_unchecked(index).span().end
1123 };
1124 Ok(RelativeSelectorList { selectors, comma_spans, span })
1125 }
1126}
1127
1128impl<'a> Parse<'a> for SelectorList<'a> {
1132 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1133 let first = input.parse::<ComplexSelector>()?;
1134 let mut span = first.span;
1135
1136 let mut selectors = input.vec_with_capacity(2);
1137 selectors.push(first);
1138 let mut comma_spans = input.vec();
1139
1140 let is_css = input.syntax == Syntax::Css;
1141 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1142 span.end = comma_span.end;
1143 comma_spans.push(comma_span);
1144 if input.syntax == Syntax::Scss {
1147 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1148 span.end = comma_span.end;
1149 comma_spans.push(comma_span);
1150 }
1151 }
1152 if input.syntax == Syntax::Sass
1156 && matches!(input.cursor.peek()?.token, Token::Indent(..))
1157 {
1158 input.eat_sass_line_continuation()?;
1159 } else if !is_css
1160 && matches!(
1161 input.cursor.peek()?.token,
1162 Token::LBrace(..) | Token::Indent(..) | Token::Linebreak(..)
1163 )
1164 {
1165 break;
1166 }
1167
1168 let selector = input.parse::<ComplexSelector>()?;
1169 span.end = selector.span.end;
1170 selectors.push(selector);
1171 }
1172
1173 debug_assert!(if is_css {
1176 selectors.len() == comma_spans.len() + 1
1177 } else {
1178 selectors.len() <= comma_spans.len() + 1
1179 });
1180
1181 Ok(SelectorList { selectors, comma_spans, span })
1182 }
1183}
1184
1185impl<'a> Parse<'a> for SimpleSelector<'a> {
1191 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1192 match input.cursor.peek()? {
1193 TokenWithSpan { token: Token::Dot(..), .. } => input.parse().map(SimpleSelector::Class),
1194 TokenWithSpan { token: Token::Hash(..) | Token::NumberSign(..), .. } => {
1195 input.parse().map(SimpleSelector::Id)
1196 }
1197 TokenWithSpan { token: Token::LBracket(..), .. } => {
1198 input.parse().map(SimpleSelector::Attribute)
1199 }
1200 TokenWithSpan { token: Token::Colon(..), .. } => {
1201 input.parse().map(SimpleSelector::PseudoClass)
1202 }
1203 TokenWithSpan { token: Token::ColonColon(..), .. } => {
1204 input.parse().map(SimpleSelector::PseudoElement)
1205 }
1206 TokenWithSpan {
1207 token:
1208 Token::Ident(..)
1209 | Token::Asterisk(..)
1210 | Token::HashLBrace(..)
1211 | Token::Bar(..)
1212 | Token::AtLBraceVar(..),
1213 ..
1214 } => input.parse().map(SimpleSelector::Type),
1215 TokenWithSpan { token: Token::Ampersand(..), .. } => {
1216 input.parse().map(SimpleSelector::Nesting)
1217 }
1218 TokenWithSpan { token: Token::Percent(..), .. }
1223 if matches!(input.syntax, Syntax::Scss | Syntax::Sass | Syntax::Css) =>
1224 {
1225 input.parse().map(SimpleSelector::SassPlaceholder)
1226 }
1227 TokenWithSpan { token: Token::Placeholder(..), .. } => {
1228 let name = input.parse::<InterpolableIdent>()?;
1229 let span = *name.span();
1230 Ok(SimpleSelector::Type(TypeSelector::TagName(TagNameSelector {
1231 name: WqName { name, prefix: None, span },
1232 span,
1233 })))
1234 }
1235 token_with_span => {
1236 Err(Error { kind: ErrorKind::ExpectSimpleSelector, span: token_with_span.span })
1237 }
1238 }
1239 }
1240}
1241
1242impl<'a> Parse<'a> for TypeSelector<'a> {
1246 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1247 enum IdentOrAsterisk<'a> {
1248 Ident(InterpolableIdent<'a>),
1249 Asterisk(Span),
1250 }
1251
1252 let ident_or_asterisk = match &input.cursor.peek()?.token {
1253 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..) => {
1254 input.parse().map(IdentOrAsterisk::Ident).map(Some)?
1255 }
1256 Token::Asterisk(..) => Some(IdentOrAsterisk::Asterisk(input.cursor.bump()?.span)),
1257 Token::Bar(..) => None,
1258 _ => unreachable!(),
1259 };
1260
1261 match input.cursor.peek()? {
1262 TokenWithSpan { token: Token::Bar(..), span }
1263 if ident_or_asterisk
1264 .as_ref()
1265 .map(|t| match t {
1266 IdentOrAsterisk::Ident(ident) => {
1267 !util::has_ws(input.source, ident.span().end, span.start)
1268 }
1269 IdentOrAsterisk::Asterisk(asterisk_span) => {
1270 !util::has_ws(input.source, asterisk_span.end, span.start)
1271 }
1272 })
1273 .unwrap_or(true) =>
1274 {
1275 let bar_token_span = input.cursor.bump()?.span;
1276
1277 let prefix = match ident_or_asterisk {
1278 Some(IdentOrAsterisk::Ident(ident)) => {
1279 let mut span = *ident.span();
1280 span.end = bar_token_span.end;
1281 NsPrefix { kind: Some(NsPrefixKind::Ident(ident)), span }
1282 }
1283 Some(IdentOrAsterisk::Asterisk(asterisk_span)) => {
1284 let mut span = asterisk_span;
1285 span.end = bar_token_span.end;
1286 NsPrefix {
1287 kind: Some(NsPrefixKind::Universal(NsPrefixUniversal {
1288 span: asterisk_span,
1289 })),
1290 span,
1291 }
1292 }
1293 None => NsPrefix { kind: None, span: bar_token_span },
1294 };
1295
1296 match input.cursor.peek()? {
1297 TokenWithSpan { token: Token::Ident(..) | Token::HashLBrace(..), .. } => {
1298 let name = input.parse::<InterpolableIdent>()?;
1299 let name_span = name.span();
1300 util::assert_no_ws(input.source, &prefix.span, name_span)?;
1301 let span = Span { start: prefix.span.start, end: name_span.end };
1302 Ok(TypeSelector::TagName(TagNameSelector {
1303 name: WqName { name, prefix: Some(prefix), span },
1304 span,
1305 }))
1306 }
1307 TokenWithSpan { token: Token::Asterisk(..), .. } => {
1308 let asterisk_span = input.cursor.bump()?.span;
1309 util::assert_no_ws(input.source, &prefix.span, &asterisk_span)?;
1310 let span = Span { start: prefix.span.start, end: asterisk_span.end };
1311 Ok(TypeSelector::Universal(UniversalSelector {
1312 prefix: Some(prefix),
1313 span,
1314 }))
1315 }
1316 TokenWithSpan { span, .. } => {
1317 Err(Error { kind: ErrorKind::ExpectTypeSelector, span: *span })
1318 }
1319 }
1320 }
1321
1322 _ => match ident_or_asterisk {
1323 Some(IdentOrAsterisk::Ident(ident)) => {
1324 let span = *ident.span();
1325 Ok(TypeSelector::TagName(TagNameSelector {
1326 name: WqName { name: ident, prefix: None, span },
1327 span,
1328 }))
1329 }
1330 Some(IdentOrAsterisk::Asterisk(span)) => {
1331 Ok(TypeSelector::Universal(UniversalSelector { prefix: None, span }))
1332 }
1333 None => unreachable!(),
1334 },
1335 }
1336 }
1337}
1338
1339impl<'a> Parser<'a> {
1340 fn parse_combinator(&mut self, pos: usize) -> PResult<Option<Combinator>> {
1344 match self.cursor.peek()? {
1345 TokenWithSpan {
1346 token:
1347 Token::Ident(..)
1348 | Token::Dot(..)
1349 | Token::Hash(..)
1350 | Token::Colon(..)
1351 | Token::ColonColon(..)
1352 | Token::LBracket(..)
1353 | Token::Asterisk(..)
1354 | Token::Ampersand(..)
1355 | Token::Bar(..) | Token::AtLBraceVar(..)
1357 | Token::NumberSign(..)
1358 | Token::HashLBrace(..)
1359 | Token::Percent(..) | Token::Placeholder(..), span,
1362 } if pos < span.start => Ok(Some(Combinator {
1363 kind: CombinatorKind::Descendant,
1364 span: Span {
1365 start: pos,
1366 end: span.start,
1367 },
1368 })),
1369 TokenWithSpan {
1370 token: Token::GreaterThan(..),
1371 ..
1372 } => Ok(Some(Combinator {
1373 kind: CombinatorKind::Child,
1374 span: self.cursor.bump()?.span,
1375 })),
1376 TokenWithSpan {
1377 token: Token::Plus(..),
1378 ..
1379 } => Ok(Some(Combinator {
1380 kind: CombinatorKind::NextSibling,
1381 span: self.cursor.bump()?.span,
1382 })),
1383 TokenWithSpan {
1384 token: Token::Tilde(..),
1385 ..
1386 } => Ok(Some(Combinator {
1387 kind: CombinatorKind::LaterSibling,
1388 span: self.cursor.bump()?.span,
1389 })),
1390 TokenWithSpan {
1391 token: Token::BarBar(..),
1392 ..
1393 } => Ok(Some(Combinator {
1394 kind: CombinatorKind::Column,
1395 span: self.cursor.bump()?.span,
1396 })),
1397 TokenWithSpan { token: Token::Solidus(..), .. }
1401 if !matches!(self.syntax, Syntax::Scss | Syntax::Sass) =>
1402 {
1403 let deep = self.try_parse(|p| {
1404 let start = p.cursor.bump()?.span; let ident_end = match p.cursor.peek()? {
1406 TokenWithSpan { token: Token::Ident(..), span }
1407 if span.start == start.end =>
1408 {
1409 p.cursor.bump()?.span.end
1410 }
1411 TokenWithSpan { span, .. } => {
1412 return Err(Error {
1413 kind: ErrorKind::TryParseError,
1414 span: *span,
1415 });
1416 }
1417 };
1418 match p.cursor.peek()? {
1419 TokenWithSpan { token: Token::Solidus(..), span }
1420 if span.start == ident_end =>
1421 {
1422 let end = p.cursor.bump()?.span.end;
1423 Ok(Span { start: start.start, end })
1424 }
1425 TokenWithSpan { span, .. } => Err(Error {
1426 kind: ErrorKind::TryParseError,
1427 span: *span,
1428 }),
1429 }
1430 });
1431 match deep {
1432 Ok(span) => Ok(Some(Combinator { kind: CombinatorKind::Deep, span })),
1433 Err(_) => Ok(None),
1434 }
1435 }
1436 TokenWithSpan {
1439 token: Token::Unknown(..),
1440 span,
1441 } if !matches!(self.syntax, Syntax::Scss | Syntax::Sass)
1442 && self.source.as_bytes().get(span.start) == Some(&b'^') =>
1443 {
1444 let start = self.cursor.bump()?.span.start;
1445 if matches!(&self.cursor.peek()?.token, Token::Unknown(..))
1446 && self.cursor.peek()?.span.start == start + 1
1447 && self.source.as_bytes().get(start + 1) == Some(&b'^')
1448 {
1449 let end = self.cursor.bump()?.span.end;
1450 Ok(Some(Combinator {
1451 kind: CombinatorKind::ShadowDescendant,
1452 span: Span { start, end },
1453 }))
1454 } else {
1455 Ok(Some(Combinator {
1456 kind: CombinatorKind::ShadowChild,
1457 span: Span { start, end: start + 1 },
1458 }))
1459 }
1460 }
1461 _ => Ok(None),
1462 }
1463 }
1464}
1465
1466fn expect_unsigned_int<'a>(input: &mut Parser<'a>) -> PResult<(token::Number<'a>, Span)> {
1467 let (number, span) = input.cursor.expect_number()?;
1468 if number.raw.chars().any(|c| !c.is_ascii_digit()) {
1469 Err(Error { kind: ErrorKind::ExpectUnsignedInteger, span })
1470 } else {
1471 Ok((number, span))
1472 }
1473}