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