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::Percentage(..), .. }
432 if input.syntax == Syntax::Less =>
433 {
434 Some(AttributeSelectorValue::Percentage(input.parse()?))
435 }
436 TokenWithSpan { token: Token::Tilde(..), .. } if input.syntax == Syntax::Less => {
437 Some(AttributeSelectorValue::LessEscapedStr(input.parse()?))
438 }
439 TokenWithSpan { token: Token::RBracket(..), span } => {
440 input.recoverable_errors.push(Error {
441 kind: ErrorKind::ExpectAttributeSelectorValue,
442 span: span.clone(),
443 });
444 None
445 }
446 token_with_span => {
447 return Err(Error {
448 kind: ErrorKind::ExpectAttributeSelectorValue,
449 span: token_with_span.span.clone(),
450 });
451 }
452 }
453 } else {
454 None
455 };
456
457 let modifier = if value.is_some() {
458 match &peek!(input).token {
459 Token::Ident(..) | Token::HashLBrace(..) => {
460 let ident = input.parse::<InterpolableIdent>()?;
461 let span = ident.span().clone();
462 Some(AttributeSelectorModifier { ident, span })
463 }
464 _ => None,
465 }
466 } else {
467 None
468 };
469
470 let end = expect!(input, RBracket).1.end;
471 Ok(AttributeSelector { name, matcher, value, modifier, span: Span { start, end } })
472 }
473}
474
475impl<'a> Parse<'a> for ClassSelector<'a> {
476 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
477 let (_, dot_span) = expect!(input, Dot);
478 let start = dot_span.start;
479 let end;
480 let placeholder = if input.options.template_placeholder.is_some() {
487 input.tokenizer.scan_placeholder()
488 } else {
489 None
490 };
491 let name = if let Some(TokenWithSpan { token: Token::Placeholder(placeholder), span }) =
492 placeholder
493 {
494 end = span.end;
495 InterpolableIdent::Placeholder((placeholder, span).into())
496 } else if input.syntax == Syntax::Css {
497 let (ident, ident_span) = expect_without_ws_or_comments!(input, Ident);
498 end = ident_span.end;
499 InterpolableIdent::Literal(input.ident(ident, ident_span))
500 } else {
501 let ident = input.parse::<InterpolableIdent>()?;
502 let ident_span = ident.span();
503 util::assert_no_ws_or_comment(&dot_span, ident_span)?;
504 end = ident_span.end;
505 ident
506 };
507
508 Ok(ClassSelector { name, span: Span { start, end } })
509 }
510}
511
512impl<'a> Parse<'a> for ComplexSelector<'a> {
513 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
514 let mut children = input.vec_with_capacity(3);
515
516 let (span, first, mut is_previous_combinator) = if let Token::GreaterThan(..)
517 | Token::Plus(..)
518 | Token::Tilde(..)
519 | Token::BarBar(..) = peek!(input).token
520 {
521 let end = input.tokenizer.current_offset();
522 if let Some(combinator) = input.parse_combinator(end)? {
523 (combinator.span.clone(), ComplexSelectorChild::Combinator(combinator), true)
524 } else {
525 return Err(Error {
526 kind: ErrorKind::ExpectSimpleSelector,
527 span: bump!(input).span,
528 });
529 }
530 } else {
531 let compound_selector = input.parse::<CompoundSelector>()?;
532 (
533 compound_selector.span.clone(),
534 ComplexSelectorChild::CompoundSelector(compound_selector),
535 false,
536 )
537 };
538 let Span { start, mut end } = span;
539
540 children.push(first);
541 let is_less = input.syntax == Syntax::Less;
542 while !matches!(
543 peek!(input).token,
544 Token::LBrace(..) | Token::Indent(..) | Token::Linebreak(..)
545 ) {
546 if is_previous_combinator {
547 let compound_selector = input.parse::<CompoundSelector>()?;
548 end = compound_selector.span.end;
549 children.push(ComplexSelectorChild::CompoundSelector(compound_selector));
550 } else if let Some(combinator) = input.parse_combinator(end)? {
551 if is_less && combinator.kind == CombinatorKind::Descendant {
552 match &peek!(input).token {
553 Token::Ident(ident) if ident.raw == "when" => break,
554 _ => {}
555 }
556 }
557 children.push(ComplexSelectorChild::Combinator(combinator));
558 } else {
559 break;
560 }
561 is_previous_combinator = !is_previous_combinator;
562 }
563
564 Ok(ComplexSelector { children, span: Span { start, end } })
565 }
566}
567
568impl<'a> Parse<'a> for CompoundSelector<'a> {
569 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
570 let first = input.parse::<SimpleSelector>()?;
571 let first_span = first.span();
572 let start = first_span.start;
573 let mut end = first_span.end;
574
575 let mut children = input.vec_with_capacity(2);
576 children.push(first);
577 loop {
578 use token::*;
579 match peek!(input) {
580 TokenWithSpan {
581 token:
582 Token::Dot(..)
583 | Token::Hash(..)
584 | Token::NumberSign(..)
585 | Token::LBracket(..)
586 | Token::Colon(..)
587 | Token::ColonColon(..)
588 | Token::Ident(..)
589 | Token::Asterisk(..)
590 | Token::HashLBrace(..)
591 | Token::Bar(..)
592 | Token::Ampersand(..)
593 | Token::AtLBraceVar(..),
594 span,
595 } if !util::has_ws(input.source, end, span.start) => {
596 let child = input.parse::<SimpleSelector>()?;
597 end = child.span().end;
598 children.push(child);
599 }
600 TokenWithSpan { token: Token::Percent(..), span }
601 if matches!(input.syntax, Syntax::Scss | Syntax::Sass)
602 && !util::has_ws(input.source, end, span.start) =>
603 {
604 let child = input.parse::<SimpleSelector>()?;
605 end = child.span().end;
606 children.push(child);
607 }
608 TokenWithSpan { token: Token::Placeholder(..), span }
609 if !util::has_ws(input.source, end, span.start) =>
610 {
611 let child = input.parse::<SimpleSelector>()?;
612 end = child.span().end;
613 children.push(child);
614 }
615 _ => break,
616 }
617 }
618
619 Ok(CompoundSelector { children, span: Span { start, end } })
620 }
621}
622
623impl<'a> Parse<'a> for CompoundSelectorList<'a> {
624 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
625 let first = input.parse::<CompoundSelector>()?;
626 let mut span = first.span.clone();
627
628 let mut selectors = arena_vec!(input; first);
629 let mut comma_spans = arena_vec!(input);
630 while let Some((_, comma_span)) = eat!(input, Comma) {
631 comma_spans.push(comma_span);
632 selectors.push(input.parse()?);
633 }
634
635 span.end = unsafe {
637 let index = selectors.len() - 1;
638 selectors.get_unchecked(index).span().end
639 };
640 Ok(CompoundSelectorList { selectors, comma_spans, span })
641 }
642}
643
644impl<'a> Parse<'a> for IdSelector<'a> {
645 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
646 match bump!(input) {
647 TokenWithSpan { token: Token::Hash(token), span } => {
648 let first_span = Span { start: span.start + 1, end: span.end };
649 let raw = token.raw;
650 if raw.starts_with(|c: char| c.is_ascii_digit())
651 || matches!(raw.as_bytes(), [b'-'] | [b'-', b'0'..=b'9', ..])
652 {
653 input
654 .recoverable_errors
655 .push(Error { kind: ErrorKind::InvalidIdSelectorName, span: span.clone() });
656 }
657 let value = if token.escaped {
658 util::handle_escape_in(raw, input.allocator())
659 } else {
660 raw
661 };
662 let first = Ident { name: value, raw: token.raw, span: first_span };
663 let name = match peek!(input) {
664 TokenWithSpan { token: Token::HashLBrace(..), span }
665 if matches!(input.syntax, Syntax::Scss | Syntax::Sass)
666 && first.span.end == span.start =>
667 {
668 match input.parse()? {
669 InterpolableIdent::SassInterpolated(mut interpolation) => {
670 interpolation.elements.insert(
671 0,
672 SassInterpolatedIdentElement::Static(
673 InterpolableIdentStaticPart {
674 value: first.name,
675 raw: first.raw,
676 span: first.span,
677 },
678 ),
679 );
680 InterpolableIdent::SassInterpolated(interpolation)
681 }
682 _ => unreachable!(),
683 }
684 }
685 _ => InterpolableIdent::Literal(first),
686 };
687 let span = Span { start: span.start, end: name.span().end };
688 Ok(IdSelector { name, span })
689 }
690 TokenWithSpan { token: Token::NumberSign(..), span } => {
691 let name = input.parse::<InterpolableIdent>()?;
692 let span = Span { start: span.start, end: name.span().end };
693 Ok(IdSelector { name, span })
694 }
695 TokenWithSpan { span, .. } => Err(Error { kind: ErrorKind::ExpectIdSelector, span }),
696 }
697 }
698}
699
700impl<'a> Parse<'a> for LanguageRange<'a> {
701 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
702 match &peek!(input).token {
703 Token::Str(..) | Token::StrTemplate(..) => input.parse().map(LanguageRange::Str),
704 _ => input.parse().map(LanguageRange::Ident),
705 }
706 }
707}
708
709impl<'a> Parse<'a> for LanguageRangeList<'a> {
710 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
711 let first = input.parse::<LanguageRange>()?;
712 let mut span = first.span().clone();
713
714 let mut ranges = arena_vec!(input; first);
715 let mut comma_spans = arena_vec!(input);
716 while let Some((_, comma_span)) = eat!(input, Comma) {
717 comma_spans.push(comma_span);
718 ranges.push(input.parse()?);
719 }
720 debug_assert_eq!(comma_spans.len() + 1, ranges.len());
721
722 if let Some(end) = ranges.last() {
723 span.end = end.span().end;
724 }
725 Ok(LanguageRangeList { ranges, comma_spans, span })
726 }
727}
728
729impl<'a> Parse<'a> for NestingSelector<'a> {
730 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
731 let (_, mut span) = expect!(input, Ampersand);
732 let suffix = match input.syntax {
733 Syntax::Css => {
734 if let Some((ident, ident_span)) = input.tokenizer.scan_ident_template()? {
735 span.end = ident_span.end;
736 Some(InterpolableIdent::Literal(input.ident(ident, ident_span)))
737 } else {
738 None
739 }
740 }
741 Syntax::Scss | Syntax::Sass => {
742 let start = span.end;
743 let elements = input.parse_sass_interpolated_ident_rest(&mut span.end)?;
744 if elements.is_empty() {
745 None
746 } else {
747 Some(InterpolableIdent::SassInterpolated(SassInterpolatedIdent {
748 elements,
749 span: Span { start, end: span.end },
750 }))
751 }
752 }
753 Syntax::Less => {
754 let start = span.end;
755 let elements = input.parse_less_interpolated_ident_rest(&mut span.end)?;
756 if elements.is_empty() {
757 None
758 } else {
759 Some(InterpolableIdent::LessInterpolated(LessInterpolatedIdent {
760 elements,
761 span: Span { start, end: span.end },
762 }))
763 }
764 }
765 };
766 Ok(NestingSelector { suffix, span })
767 }
768}
769
770impl<'a> Parse<'a> for Nth<'a> {
772 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
773 let index = input.parse::<NthIndex>()?;
774 let mut span = index.span().clone();
775 let matcher = match &peek!(input).token {
776 Token::Ident(ident) if ident.name().eq_ignore_ascii_case("of") => {
777 let matcher = input.parse::<NthMatcher>()?;
778 span.end = matcher.span.end;
779 Some(matcher)
780 }
781 _ => None,
782 };
783
784 Ok(Nth { index, matcher, span })
785 }
786}
787
788impl<'a> Parse<'a> for NthIndex<'a> {
789 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
790 match &peek!(input).token {
791 Token::Ident(ident) => {
792 let name = ident.name();
793 if name.eq_ignore_ascii_case("odd") {
794 input.parse().map(NthIndex::Odd)
795 } else if name.eq_ignore_ascii_case("even") {
796 input.parse().map(NthIndex::Even)
797 } else {
798 input.parse().map(NthIndex::AnPlusB)
799 }
800 }
801 Token::Number(..) => {
802 let number = input.parse::<Number>()?;
803 if number.value.fract() == 0.0 {
804 Ok(NthIndex::Integer(number))
805 } else {
806 Err(Error { kind: ErrorKind::ExpectInteger, span: number.span })
807 }
808 }
809 _ => input.parse().map(NthIndex::AnPlusB),
810 }
811 }
812}
813
814impl<'a> Parse<'a> for NthMatcher<'a> {
815 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
816 let (ident, mut span) = expect!(input, Ident);
817 if !ident.name().eq_ignore_ascii_case("of") {
818 return Err(Error { kind: ErrorKind::ExpectNthOf, span });
819 }
820
821 let selector = if matches!(&peek!(input).token, Token::RParen(..)) {
822 None
823 } else {
824 let selector = input.parse::<SelectorList>()?;
825 span.end = selector.span.end;
826 Some(selector)
827 };
828
829 Ok(NthMatcher { selector, span })
830 }
831}
832
833impl<'a> Parse<'a> for PseudoClassSelector<'a> {
834 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
835 let (_, colon_span) = expect!(input, Colon);
836 let name = input.parse::<InterpolableIdent>()?;
837 let name_span = name.span();
838 util::assert_no_ws(input.source, &colon_span, name_span)?;
839
840 let mut end = name_span.end;
841
842 let arg = match peek!(input) {
843 TokenWithSpan { token: Token::LParen(..), span: l_paren } if l_paren.start == end => {
844 let l_paren = l_paren.clone();
845 bump!(input);
846 let kind = match &name {
847 InterpolableIdent::Literal(Ident { name, .. })
848 if name.eq_ignore_ascii_case("nth-child")
849 || name.eq_ignore_ascii_case("nth-last-child") =>
850 {
851 if input.syntax == Syntax::Css {
852 input.parse().map(PseudoClassSelectorArgKind::Nth)?
853 } else if let Ok(nth) = input.try_parse(Nth::parse) {
854 PseudoClassSelectorArgKind::Nth(nth)
855 } else {
856 input
857 .parse_tokens_in_parens()
858 .map(PseudoClassSelectorArgKind::TokenSeq)?
859 }
860 }
861 InterpolableIdent::Literal(Ident { name, .. })
862 if name.eq_ignore_ascii_case("nth-of-type")
863 || name.eq_ignore_ascii_case("nth-last-of-type")
864 || name.eq_ignore_ascii_case("nth-col")
865 || name.eq_ignore_ascii_case("nth-last-col") =>
866 'pseudo_arg: {
867 let nth = if input.syntax == Syntax::Css {
868 input.parse()?
869 } else if let Ok(nth) = input.try_parse(Nth::parse) {
870 nth
871 } else {
872 break 'pseudo_arg input
873 .parse_tokens_in_parens()
874 .map(PseudoClassSelectorArgKind::TokenSeq)?;
875 };
876 if let Some(NthMatcher { span, .. }) = &nth.matcher {
877 input.recoverable_errors.push(Error {
878 kind: ErrorKind::UnexpectedNthMatcher,
879 span: span.clone(),
880 });
881 }
882 PseudoClassSelectorArgKind::Nth(nth)
883 }
884 InterpolableIdent::Literal(Ident { name, .. })
885 if name.eq_ignore_ascii_case("not")
886 || name.eq_ignore_ascii_case("is")
887 || name.eq_ignore_ascii_case("where")
888 || name.eq_ignore_ascii_case("matches")
889 || name.eq_ignore_ascii_case("global") =>
890 {
891 input.parse().map(PseudoClassSelectorArgKind::SelectorList)?
892 }
893 InterpolableIdent::Literal(Ident { name, .. })
894 if name.eq_ignore_ascii_case("has") =>
895 {
896 input.parse().map(PseudoClassSelectorArgKind::RelativeSelectorList)?
897 }
898 InterpolableIdent::Literal(Ident { name, .. })
899 if name.eq_ignore_ascii_case("dir") =>
900 {
901 input.parse().map(PseudoClassSelectorArgKind::Ident)?
902 }
903 InterpolableIdent::Literal(Ident { name, .. })
904 if name.eq_ignore_ascii_case("lang") =>
905 {
906 input.parse().map(PseudoClassSelectorArgKind::LanguageRangeList)?
907 }
908 InterpolableIdent::Literal(Ident { name, .. })
909 if name.eq_ignore_ascii_case("-moz-any")
910 || name.eq_ignore_ascii_case("-webkit-any")
911 || name.eq_ignore_ascii_case("current")
912 || name.eq_ignore_ascii_case("past")
913 || name.eq_ignore_ascii_case("future") =>
914 {
915 input.parse().map(PseudoClassSelectorArgKind::CompoundSelectorList)?
916 }
917 InterpolableIdent::Literal(Ident { name, .. })
918 if name.eq_ignore_ascii_case("host")
919 || name.eq_ignore_ascii_case("host-context") =>
920 {
921 input.parse().map(PseudoClassSelectorArgKind::CompoundSelector)?
922 }
923 InterpolableIdent::Literal(Ident { name, .. })
924 if input.syntax == Syntax::Less && *name == "extend" =>
925 {
926 input.parse().map(PseudoClassSelectorArgKind::LessExtendList)?
927 }
928 _ => {
929 input.parse_tokens_in_parens().map(PseudoClassSelectorArgKind::TokenSeq)?
930 }
931 };
932
933 let r_paren = expect!(input, RParen).1;
934 end = r_paren.end;
935 let span = Span { start: l_paren.start, end: r_paren.end };
936 Some(PseudoClassSelectorArg { kind, l_paren, r_paren, span })
937 }
938 _ => None,
939 };
940
941 let span = Span { start: colon_span.start, end };
942 Ok(PseudoClassSelector { name, arg, span })
943 }
944}
945
946impl<'a> Parse<'a> for PseudoElementSelector<'a> {
947 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
948 let (_, colon_colon_span) = expect!(input, ColonColon);
949 let mut end;
950 let name = if input.syntax == Syntax::Css {
951 let (ident, ident_span) = expect!(input, Ident);
952 end = ident_span.end;
953 util::assert_no_ws(input.source, &colon_colon_span, &ident_span)?;
954 InterpolableIdent::Literal(input.ident(ident, ident_span))
955 } else {
956 let name = input.parse::<InterpolableIdent>()?;
957 let name_span = name.span();
958 end = name_span.end;
959 util::assert_no_ws(input.source, &colon_colon_span, name_span)?;
960 name
961 };
962
963 let arg = match peek!(input) {
964 TokenWithSpan { token: Token::LParen(..), span: l_paren } if l_paren.start == end => {
965 let l_paren = l_paren.clone();
966 bump!(input);
967 let kind = match &name {
968 InterpolableIdent::Literal(Ident { name, .. })
969 if name.eq_ignore_ascii_case("part") =>
970 {
971 input.parse().map(PseudoElementSelectorArgKind::Ident)?
972 }
973 InterpolableIdent::Literal(Ident { name, .. })
974 if name.eq_ignore_ascii_case("cue")
975 || name.eq_ignore_ascii_case("cue-region")
976 || name.eq_ignore_ascii_case("slotted") =>
977 {
978 input.parse().map(PseudoElementSelectorArgKind::CompoundSelector)?
979 }
980 _ => input
981 .parse_tokens_in_parens()
982 .map(PseudoElementSelectorArgKind::TokenSeq)?,
983 };
984
985 let r_paren = expect!(input, RParen).1;
986 end = r_paren.end;
987 let span = Span { start: l_paren.start, end: r_paren.end };
988 Some(PseudoElementSelectorArg { kind, l_paren, r_paren, span })
989 }
990 _ => None,
991 };
992
993 let span = Span { start: colon_colon_span.start, end };
994 Ok(PseudoElementSelector { name, arg, span })
995 }
996}
997
998impl<'a> Parse<'a> for RelativeSelector<'a> {
999 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1000 let pos = input.tokenizer.current_offset();
1001 let combinator = match input.parse_combinator(pos)? {
1002 Some(Combinator { kind: CombinatorKind::Descendant, .. }) => None,
1003 combinator => combinator,
1004 };
1005 let complex_selector = input.parse::<ComplexSelector>()?;
1006 let mut span = complex_selector.span.clone();
1007 if let Some(combinator) = &combinator {
1008 span.start = combinator.span.start;
1009 }
1010 Ok(RelativeSelector { combinator, complex_selector, span })
1011 }
1012}
1013
1014impl<'a> Parse<'a> for RelativeSelectorList<'a> {
1015 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1016 let first = input.parse::<RelativeSelector>()?;
1017 let mut span = first.span.clone();
1018
1019 let mut selectors = arena_vec!(input; first);
1020 let mut comma_spans = arena_vec!(input);
1021 while let Some((_, comma_span)) = eat!(input, Comma) {
1022 comma_spans.push(comma_span);
1023 selectors.push(input.parse()?);
1024 }
1025
1026 span.end = unsafe {
1028 let index = selectors.len() - 1;
1029 selectors.get_unchecked(index).span().end
1030 };
1031 Ok(RelativeSelectorList { selectors, comma_spans, span })
1032 }
1033}
1034
1035impl<'a> Parse<'a> for SelectorList<'a> {
1036 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1037 let first = input.parse::<ComplexSelector>()?;
1038 let mut span = first.span.clone();
1039
1040 let mut selectors = input.vec_with_capacity(2);
1041 selectors.push(first);
1042 let mut comma_spans = arena_vec!(input);
1043
1044 let is_css = input.syntax == Syntax::Css;
1045 while let Some((_, comma_span)) = eat!(input, Comma) {
1046 span.end = comma_span.end;
1047 comma_spans.push(comma_span);
1048 if !is_css
1049 && matches!(
1050 peek!(input).token,
1051 Token::LBrace(..) | Token::Indent(..) | Token::Linebreak(..)
1052 )
1053 {
1054 break;
1055 }
1056
1057 let selector = input.parse::<ComplexSelector>()?;
1058 span.end = selector.span.end;
1059 selectors.push(selector);
1060 }
1061
1062 debug_assert!(if is_css {
1063 selectors.len() - comma_spans.len() == 1
1064 } else {
1065 selectors.len() - comma_spans.len() <= 1
1066 });
1067
1068 Ok(SelectorList { selectors, comma_spans, span })
1069 }
1070}
1071
1072impl<'a> Parse<'a> for SimpleSelector<'a> {
1074 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1075 match peek!(input) {
1076 TokenWithSpan { token: Token::Dot(..), .. } => input.parse().map(SimpleSelector::Class),
1077 TokenWithSpan { token: Token::Hash(..) | Token::NumberSign(..), .. } => {
1078 input.parse().map(SimpleSelector::Id)
1079 }
1080 TokenWithSpan { token: Token::LBracket(..), .. } => {
1081 input.parse().map(SimpleSelector::Attribute)
1082 }
1083 TokenWithSpan { token: Token::Colon(..), .. } => {
1084 input.parse().map(SimpleSelector::PseudoClass)
1085 }
1086 TokenWithSpan { token: Token::ColonColon(..), .. } => {
1087 input.parse().map(SimpleSelector::PseudoElement)
1088 }
1089 TokenWithSpan {
1090 token:
1091 Token::Ident(..)
1092 | Token::Asterisk(..)
1093 | Token::HashLBrace(..)
1094 | Token::Bar(..)
1095 | Token::AtLBraceVar(..),
1096 ..
1097 } => input.parse().map(SimpleSelector::Type),
1098 TokenWithSpan { token: Token::Ampersand(..), .. } => {
1099 input.parse().map(SimpleSelector::Nesting)
1100 }
1101 TokenWithSpan { token: Token::Percent(..), .. }
1102 if matches!(input.syntax, Syntax::Scss | Syntax::Sass) =>
1103 {
1104 input.parse().map(SimpleSelector::SassPlaceholder)
1105 }
1106 TokenWithSpan { token: Token::Placeholder(..), .. } => {
1107 let name = input.parse::<InterpolableIdent>()?;
1108 let span = name.span().clone();
1109 Ok(SimpleSelector::Type(TypeSelector::TagName(TagNameSelector {
1110 name: WqName { name, prefix: None, span: span.clone() },
1111 span,
1112 })))
1113 }
1114 token_with_span => Err(Error {
1115 kind: ErrorKind::ExpectSimpleSelector,
1116 span: token_with_span.span.clone(),
1117 }),
1118 }
1119 }
1120}
1121
1122impl<'a> Parse<'a> for TypeSelector<'a> {
1123 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
1124 enum IdentOrAsterisk<'a> {
1125 Ident(InterpolableIdent<'a>),
1126 Asterisk(Span),
1127 }
1128
1129 let ident_or_asterisk = match &peek!(input).token {
1130 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..) => {
1131 input.parse().map(IdentOrAsterisk::Ident).map(Some)?
1132 }
1133 Token::Asterisk(..) => Some(IdentOrAsterisk::Asterisk(bump!(input).span)),
1134 Token::Bar(..) => None,
1135 _ => unreachable!(),
1136 };
1137
1138 match peek!(input) {
1139 TokenWithSpan { token: Token::Bar(..), span }
1140 if ident_or_asterisk
1141 .as_ref()
1142 .map(|t| match t {
1143 IdentOrAsterisk::Ident(ident) => {
1144 !util::has_ws(input.source, ident.span().end, span.start)
1145 }
1146 IdentOrAsterisk::Asterisk(asterisk_span) => {
1147 !util::has_ws(input.source, asterisk_span.end, span.start)
1148 }
1149 })
1150 .unwrap_or(true) =>
1151 {
1152 let bar_token_span = bump!(input).span;
1153
1154 let prefix = match ident_or_asterisk {
1155 Some(IdentOrAsterisk::Ident(ident)) => {
1156 let mut span = ident.span().clone();
1157 span.end = bar_token_span.end;
1158 NsPrefix { kind: Some(NsPrefixKind::Ident(ident)), span }
1159 }
1160 Some(IdentOrAsterisk::Asterisk(asterisk_span)) => {
1161 let mut span = asterisk_span.clone();
1162 span.end = bar_token_span.end;
1163 NsPrefix {
1164 kind: Some(NsPrefixKind::Universal(NsPrefixUniversal {
1165 span: asterisk_span,
1166 })),
1167 span,
1168 }
1169 }
1170 None => NsPrefix { kind: None, span: bar_token_span },
1171 };
1172
1173 match peek!(input) {
1174 TokenWithSpan { token: Token::Ident(..) | Token::HashLBrace(..), .. } => {
1175 let name = input.parse::<InterpolableIdent>()?;
1176 let name_span = name.span();
1177 util::assert_no_ws(input.source, &prefix.span, name_span)?;
1178 let span = Span { start: prefix.span.start, end: name_span.end };
1179 Ok(TypeSelector::TagName(TagNameSelector {
1180 name: WqName { name, prefix: Some(prefix), span: span.clone() },
1181 span,
1182 }))
1183 }
1184 TokenWithSpan { token: Token::Asterisk(..), .. } => {
1185 let asterisk_span = bump!(input).span;
1186 util::assert_no_ws(input.source, &prefix.span, &asterisk_span)?;
1187 let span = Span { start: prefix.span.start, end: asterisk_span.end };
1188 Ok(TypeSelector::Universal(UniversalSelector {
1189 prefix: Some(prefix),
1190 span,
1191 }))
1192 }
1193 TokenWithSpan { span, .. } => {
1194 Err(Error { kind: ErrorKind::ExpectTypeSelector, span: span.clone() })
1195 }
1196 }
1197 }
1198
1199 _ => match ident_or_asterisk {
1200 Some(IdentOrAsterisk::Ident(ident)) => {
1201 let span = ident.span().clone();
1202 Ok(TypeSelector::TagName(TagNameSelector {
1203 name: WqName { name: ident, prefix: None, span: span.clone() },
1204 span,
1205 }))
1206 }
1207 Some(IdentOrAsterisk::Asterisk(span)) => {
1208 Ok(TypeSelector::Universal(UniversalSelector { prefix: None, span }))
1209 }
1210 None => unreachable!(),
1211 },
1212 }
1213 }
1214}
1215
1216impl<'a> Parser<'a> {
1217 fn parse_combinator(&mut self, pos: usize) -> PResult<Option<Combinator>> {
1218 match peek!(self) {
1219 TokenWithSpan {
1220 token:
1221 Token::Ident(..)
1222 | Token::Dot(..)
1223 | Token::Hash(..)
1224 | Token::Colon(..)
1225 | Token::ColonColon(..)
1226 | Token::LBracket(..)
1227 | Token::Asterisk(..)
1228 | Token::Ampersand(..)
1229 | Token::Bar(..) | Token::AtLBraceVar(..)
1231 | Token::NumberSign(..)
1232 | Token::HashLBrace(..)
1233 | Token::Placeholder(..), span,
1235 } if pos < span.start => Ok(Some(Combinator {
1236 kind: CombinatorKind::Descendant,
1237 span: Span {
1238 start: pos,
1239 end: span.start,
1240 },
1241 })),
1242 TokenWithSpan {
1243 token: Token::GreaterThan(..),
1244 ..
1245 } => Ok(Some(Combinator {
1246 kind: CombinatorKind::Child,
1247 span: bump!(self).span,
1248 })),
1249 TokenWithSpan {
1250 token: Token::Plus(..),
1251 ..
1252 } => Ok(Some(Combinator {
1253 kind: CombinatorKind::NextSibling,
1254 span: bump!(self).span,
1255 })),
1256 TokenWithSpan {
1257 token: Token::Tilde(..),
1258 ..
1259 } => Ok(Some(Combinator {
1260 kind: CombinatorKind::LaterSibling,
1261 span: bump!(self).span,
1262 })),
1263 TokenWithSpan {
1264 token: Token::BarBar(..),
1265 ..
1266 } => Ok(Some(Combinator {
1267 kind: CombinatorKind::Column,
1268 span: bump!(self).span,
1269 })),
1270 _ => Ok(None),
1271 }
1272 }
1273}
1274
1275fn expect_unsigned_int<'a>(input: &mut Parser<'a>) -> PResult<(token::Number<'a>, Span)> {
1276 let (number, span) = expect!(input, Number);
1277 if number.raw.chars().any(|c| !c.is_ascii_digit()) {
1278 Err(Error { kind: ErrorKind::ExpectUnsignedInteger, span })
1279 } else {
1280 Ok((number, span))
1281 }
1282}