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