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::SelectorList)?
1005 }
1006 InterpolableIdent::Literal(Ident { name, .. })
1007 if input.syntax == Syntax::Less && *name == "extend" =>
1008 {
1009 input.parse().map(PseudoClassSelectorArgKind::LessExtendList)?
1010 }
1011 _ => {
1012 input.parse_tokens_in_parens().map(PseudoClassSelectorArgKind::TokenSeq)?
1013 }
1014 };
1015
1016 let r_paren = input.cursor.expect_r_paren()?.1;
1017 end = r_paren.end;
1018 let span = Span { start: l_paren.start, end: r_paren.end };
1019 Some(PseudoClassSelectorArg { kind, l_paren, r_paren, span })
1020 }
1021 _ => None,
1022 };
1023
1024 let span = Span { start: colon_span.start, end };
1025 Ok(PseudoClassSelector { name, arg, span })
1026 }
1027}
1028
1029impl<'a> Parse<'a> for PseudoElementSelector<'a> {
1034 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1035 let (_, colon_colon_span) = input.cursor.expect_colon_colon()?;
1036 let mut end;
1037 let name = if input.syntax == Syntax::Css {
1038 let (ident, ident_span) = input.cursor.expect_ident()?;
1039 end = ident_span.end;
1040 util::assert_no_ws(input.source, &colon_colon_span, &ident_span)?;
1041 InterpolableIdent::Literal(input.ident(ident, ident_span))
1042 } else {
1043 let name = input.parse::<InterpolableIdent>()?;
1044 let name_span = name.span();
1045 end = name_span.end;
1046 util::assert_no_ws(input.source, &colon_colon_span, name_span)?;
1047 name
1048 };
1049
1050 let arg = match input.cursor.peek()? {
1051 TokenWithSpan { token: Token::LParen(..), span: l_paren } if l_paren.start == end => {
1052 let l_paren = *l_paren;
1053 input.cursor.bump()?;
1054 let kind = match &name {
1055 InterpolableIdent::Literal(Ident { name, .. })
1056 if name.eq_ignore_ascii_case("part") =>
1057 {
1058 let first = input.parse::<InterpolableIdent>()?;
1061 if matches!(
1062 input.cursor.peek()?.token,
1063 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..)
1064 ) {
1065 let mut span = *first.span();
1066 let mut idents = input.vec_with_capacity(2);
1067 idents.push(first);
1068 while matches!(
1069 input.cursor.peek()?.token,
1070 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..)
1071 ) {
1072 let ident = input.parse::<InterpolableIdent>()?;
1073 span.end = ident.span().end;
1074 idents.push(ident);
1075 }
1076 PseudoElementSelectorArgKind::IdentList(IdentList { idents, span })
1077 } else {
1078 PseudoElementSelectorArgKind::Ident(first)
1079 }
1080 }
1081 InterpolableIdent::Literal(Ident { name, .. })
1082 if name.eq_ignore_ascii_case("cue")
1083 || name.eq_ignore_ascii_case("cue-region") =>
1084 {
1085 input.parse().map(PseudoElementSelectorArgKind::CompoundSelector)?
1086 }
1087 InterpolableIdent::Literal(Ident { name, .. })
1088 if name.eq_ignore_ascii_case("slotted") =>
1089 {
1090 input.parse().map(PseudoElementSelectorArgKind::CompoundSelectorList)?
1093 }
1094 _ => input
1095 .parse_tokens_in_parens()
1096 .map(PseudoElementSelectorArgKind::TokenSeq)?,
1097 };
1098
1099 let r_paren = input.cursor.expect_r_paren()?.1;
1100 end = r_paren.end;
1101 let span = Span { start: l_paren.start, end: r_paren.end };
1102 Some(PseudoElementSelectorArg { kind, l_paren, r_paren, span })
1103 }
1104 _ => None,
1105 };
1106
1107 let span = Span { start: colon_colon_span.start, end };
1108 Ok(PseudoElementSelector { name, arg, span })
1109 }
1110}
1111
1112impl<'a> Parse<'a> for RelativeSelector<'a> {
1114 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1115 let pos = input.cursor.tokenizer.current_offset();
1116 let combinator = match input.parse_combinator(pos)? {
1117 Some(Combinator { kind: CombinatorKind::Descendant, .. }) => None,
1118 combinator => combinator,
1119 };
1120 let complex_selector = input.parse::<ComplexSelector>()?;
1121 let mut span = complex_selector.span;
1122 if let Some(combinator) = &combinator {
1123 span.start = combinator.span.start;
1124 }
1125 Ok(RelativeSelector { combinator, complex_selector, span })
1126 }
1127}
1128
1129impl<'a> Parse<'a> for RelativeSelectorList<'a> {
1131 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1132 let first = input.parse::<RelativeSelector>()?;
1133 let mut span = first.span;
1134
1135 let mut selectors = input.vec1(first);
1136 let mut comma_spans = input.vec();
1137 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1138 comma_spans.push(comma_span);
1139 selectors.push(input.parse()?);
1140 }
1141
1142 span.end = unsafe {
1144 let index = selectors.len() - 1;
1145 selectors.get_unchecked(index).span().end
1146 };
1147 Ok(RelativeSelectorList { selectors, comma_spans, span })
1148 }
1149}
1150
1151impl<'a> Parse<'a> for SelectorList<'a> {
1155 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1156 let first = input.parse::<ComplexSelector>()?;
1157 let mut span = first.span;
1158
1159 let mut selectors = input.vec_with_capacity(2);
1160 selectors.push(first);
1161 let mut comma_spans = input.vec();
1162
1163 let is_css = input.syntax == Syntax::Css;
1164 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1165 span.end = comma_span.end;
1166 comma_spans.push(comma_span);
1167 if input.syntax == Syntax::Scss {
1170 while let Some((_, comma_span)) = input.cursor.eat_comma()? {
1171 span.end = comma_span.end;
1172 comma_spans.push(comma_span);
1173 }
1174 }
1175 if input.syntax == Syntax::Sass
1179 && matches!(input.cursor.peek()?.token, Token::Indent(..))
1180 {
1181 input.eat_sass_line_continuation()?;
1182 } else if !is_css
1183 && matches!(
1184 input.cursor.peek()?.token,
1185 Token::LBrace(..) | Token::Indent(..) | Token::Linebreak(..)
1186 )
1187 {
1188 break;
1189 }
1190
1191 let selector = input.parse::<ComplexSelector>()?;
1192 span.end = selector.span.end;
1193 selectors.push(selector);
1194 }
1195
1196 debug_assert!(if is_css {
1199 selectors.len() == comma_spans.len() + 1
1200 } else {
1201 selectors.len() <= comma_spans.len() + 1
1202 });
1203
1204 Ok(SelectorList { selectors, comma_spans, span })
1205 }
1206}
1207
1208impl<'a> Parse<'a> for SimpleSelector<'a> {
1214 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1215 match input.cursor.peek()? {
1216 TokenWithSpan { token: Token::Dot(..), .. } => input.parse().map(SimpleSelector::Class),
1217 TokenWithSpan { token: Token::Hash(..) | Token::NumberSign(..), .. } => {
1218 input.parse().map(SimpleSelector::Id)
1219 }
1220 TokenWithSpan { token: Token::LBracket(..), .. } => {
1221 let selector = input.parse()?;
1222 Ok(SimpleSelector::Attribute(input.alloc(selector)))
1223 }
1224 TokenWithSpan { token: Token::Colon(..), .. } => {
1225 let selector = input.parse()?;
1226 Ok(SimpleSelector::PseudoClass(input.alloc(selector)))
1227 }
1228 TokenWithSpan { token: Token::ColonColon(..), .. } => {
1229 let selector = input.parse()?;
1230 Ok(SimpleSelector::PseudoElement(input.alloc(selector)))
1231 }
1232 TokenWithSpan {
1233 token:
1234 Token::Ident(..)
1235 | Token::Asterisk(..)
1236 | Token::HashLBrace(..)
1237 | Token::Bar(..)
1238 | Token::AtLBraceVar(..),
1239 ..
1240 } => input.parse().map(SimpleSelector::Type),
1241 TokenWithSpan { token: Token::Ampersand(..), .. } => {
1242 input.parse().map(SimpleSelector::Nesting)
1243 }
1244 TokenWithSpan { token: Token::Percent(..), .. }
1249 if matches!(input.syntax, Syntax::Scss | Syntax::Sass | Syntax::Css) =>
1250 {
1251 input.parse().map(SimpleSelector::SassPlaceholder)
1252 }
1253 TokenWithSpan { token: Token::Placeholder(..), .. } => {
1254 let name = input.parse::<InterpolableIdent>()?;
1255 let span = *name.span();
1256 Ok(SimpleSelector::Type(TypeSelector::TagName(TagNameSelector {
1257 name: WqName { name, prefix: None, span },
1258 span,
1259 })))
1260 }
1261 token_with_span => {
1262 Err(Error { kind: ErrorKind::ExpectSimpleSelector, span: token_with_span.span })
1263 }
1264 }
1265 }
1266}
1267
1268impl<'a> Parse<'a> for TypeSelector<'a> {
1272 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1273 enum IdentOrAsterisk<'a> {
1274 Ident(InterpolableIdent<'a>),
1275 Asterisk(Span),
1276 }
1277
1278 let ident_or_asterisk = match &input.cursor.peek()?.token {
1279 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..) => {
1280 input.parse().map(IdentOrAsterisk::Ident).map(Some)?
1281 }
1282 Token::Asterisk(..) => Some(IdentOrAsterisk::Asterisk(input.cursor.bump()?.span)),
1283 Token::Bar(..) => None,
1284 _ => unreachable!(),
1285 };
1286
1287 match input.cursor.peek()? {
1288 TokenWithSpan { token: Token::Bar(..), span }
1289 if ident_or_asterisk
1290 .as_ref()
1291 .map(|t| match t {
1292 IdentOrAsterisk::Ident(ident) => {
1293 !util::has_ws(input.source, ident.span().end, span.start)
1294 }
1295 IdentOrAsterisk::Asterisk(asterisk_span) => {
1296 !util::has_ws(input.source, asterisk_span.end, span.start)
1297 }
1298 })
1299 .unwrap_or(true) =>
1300 {
1301 let bar_token_span = input.cursor.bump()?.span;
1302
1303 let prefix = match ident_or_asterisk {
1304 Some(IdentOrAsterisk::Ident(ident)) => {
1305 let mut span = *ident.span();
1306 span.end = bar_token_span.end;
1307 NsPrefix { kind: Some(NsPrefixKind::Ident(ident)), span }
1308 }
1309 Some(IdentOrAsterisk::Asterisk(asterisk_span)) => {
1310 let mut span = asterisk_span;
1311 span.end = bar_token_span.end;
1312 NsPrefix {
1313 kind: Some(NsPrefixKind::Universal(NsPrefixUniversal {
1314 span: asterisk_span,
1315 })),
1316 span,
1317 }
1318 }
1319 None => NsPrefix { kind: None, span: bar_token_span },
1320 };
1321
1322 match input.cursor.peek()? {
1323 TokenWithSpan { token: Token::Ident(..) | Token::HashLBrace(..), .. } => {
1324 let name = input.parse::<InterpolableIdent>()?;
1325 let name_span = name.span();
1326 util::assert_no_ws(input.source, &prefix.span, name_span)?;
1327 let span = Span { start: prefix.span.start, end: name_span.end };
1328 Ok(TypeSelector::TagName(TagNameSelector {
1329 name: WqName { name, prefix: Some(prefix), span },
1330 span,
1331 }))
1332 }
1333 TokenWithSpan { token: Token::Asterisk(..), .. } => {
1334 let asterisk_span = input.cursor.bump()?.span;
1335 util::assert_no_ws(input.source, &prefix.span, &asterisk_span)?;
1336 let span = Span { start: prefix.span.start, end: asterisk_span.end };
1337 Ok(TypeSelector::Universal(UniversalSelector {
1338 prefix: Some(prefix),
1339 span,
1340 }))
1341 }
1342 TokenWithSpan { span, .. } => {
1343 Err(Error { kind: ErrorKind::ExpectTypeSelector, span: *span })
1344 }
1345 }
1346 }
1347
1348 _ => match ident_or_asterisk {
1349 Some(IdentOrAsterisk::Ident(ident)) => {
1350 let span = *ident.span();
1351 Ok(TypeSelector::TagName(TagNameSelector {
1352 name: WqName { name: ident, prefix: None, span },
1353 span,
1354 }))
1355 }
1356 Some(IdentOrAsterisk::Asterisk(span)) => {
1357 Ok(TypeSelector::Universal(UniversalSelector { prefix: None, span }))
1358 }
1359 None => unreachable!(),
1360 },
1361 }
1362 }
1363}
1364
1365impl<'a> Parser<'a> {
1366 fn parse_combinator(&mut self, pos: usize) -> PResult<Option<Combinator>> {
1370 match self.cursor.peek()? {
1371 TokenWithSpan {
1372 token:
1373 Token::Ident(..)
1374 | Token::Dot(..)
1375 | Token::Hash(..)
1376 | Token::Colon(..)
1377 | Token::ColonColon(..)
1378 | Token::LBracket(..)
1379 | Token::Asterisk(..)
1380 | Token::Ampersand(..)
1381 | Token::Bar(..) | Token::AtLBraceVar(..)
1383 | Token::NumberSign(..)
1384 | Token::HashLBrace(..)
1385 | Token::Percent(..) | Token::Placeholder(..), span,
1388 } if pos < span.start => Ok(Some(Combinator {
1389 kind: CombinatorKind::Descendant,
1390 span: Span {
1391 start: pos,
1392 end: span.start,
1393 },
1394 })),
1395 TokenWithSpan {
1396 token: Token::GreaterThan(..),
1397 ..
1398 } => Ok(Some(Combinator {
1399 kind: CombinatorKind::Child,
1400 span: self.cursor.bump()?.span,
1401 })),
1402 TokenWithSpan {
1403 token: Token::Plus(..),
1404 ..
1405 } => Ok(Some(Combinator {
1406 kind: CombinatorKind::NextSibling,
1407 span: self.cursor.bump()?.span,
1408 })),
1409 TokenWithSpan {
1410 token: Token::Tilde(..),
1411 ..
1412 } => Ok(Some(Combinator {
1413 kind: CombinatorKind::LaterSibling,
1414 span: self.cursor.bump()?.span,
1415 })),
1416 TokenWithSpan {
1417 token: Token::BarBar(..),
1418 ..
1419 } => Ok(Some(Combinator {
1420 kind: CombinatorKind::Column,
1421 span: self.cursor.bump()?.span,
1422 })),
1423 TokenWithSpan { token: Token::Solidus(..), .. }
1427 if !matches!(self.syntax, Syntax::Scss | Syntax::Sass) =>
1428 {
1429 let deep = self.try_parse(|p| {
1430 let start = p.cursor.bump()?.span; let ident_end = match p.cursor.peek()? {
1432 TokenWithSpan { token: Token::Ident(..), span }
1433 if span.start == start.end =>
1434 {
1435 p.cursor.bump()?.span.end
1436 }
1437 TokenWithSpan { span, .. } => {
1438 return Err(Error {
1439 kind: ErrorKind::TryParseError,
1440 span: *span,
1441 });
1442 }
1443 };
1444 match p.cursor.peek()? {
1445 TokenWithSpan { token: Token::Solidus(..), span }
1446 if span.start == ident_end =>
1447 {
1448 let end = p.cursor.bump()?.span.end;
1449 Ok(Span { start: start.start, end })
1450 }
1451 TokenWithSpan { span, .. } => Err(Error {
1452 kind: ErrorKind::TryParseError,
1453 span: *span,
1454 }),
1455 }
1456 });
1457 match deep {
1458 Ok(span) => Ok(Some(Combinator { kind: CombinatorKind::Deep, span })),
1459 Err(_) => Ok(None),
1460 }
1461 }
1462 TokenWithSpan {
1465 token: Token::Unknown(..),
1466 span,
1467 } if !matches!(self.syntax, Syntax::Scss | Syntax::Sass)
1468 && self.source.as_bytes().get(span.start) == Some(&b'^') =>
1469 {
1470 let start = self.cursor.bump()?.span.start;
1471 if matches!(&self.cursor.peek()?.token, Token::Unknown(..))
1472 && self.cursor.peek()?.span.start == start + 1
1473 && self.source.as_bytes().get(start + 1) == Some(&b'^')
1474 {
1475 let end = self.cursor.bump()?.span.end;
1476 Ok(Some(Combinator {
1477 kind: CombinatorKind::ShadowDescendant,
1478 span: Span { start, end },
1479 }))
1480 } else {
1481 Ok(Some(Combinator {
1482 kind: CombinatorKind::ShadowChild,
1483 span: Span { start, end: start + 1 },
1484 }))
1485 }
1486 }
1487 _ => Ok(None),
1488 }
1489 }
1490}
1491
1492fn expect_unsigned_int<'a>(input: &mut Parser<'a>) -> PResult<(token::Number<'a>, Span)> {
1493 let (number, span) = input.cursor.expect_number()?;
1494 if number.raw.chars().any(|c| !c.is_ascii_digit()) {
1495 Err(Error { kind: ErrorKind::ExpectUnsignedInteger, span })
1496 } else {
1497 Ok((number, span))
1498 }
1499}