1use crate::{
2 Cursor, CursorSink, Kind, KindSet, Parse, Parser, Peek, Result, Span, ToNormalisedValue, ToNumberValue, Token,
3};
4
5macro_rules! cursor_wrapped {
6 ($ident:ident) => {
7 impl $crate::ToCursors for $ident {
8 fn to_cursors(&self, s: &mut impl CursorSink) {
9 s.append((*self).into());
10 }
11 }
12
13 impl From<$ident> for $crate::Cursor {
14 fn from(value: $ident) -> Self {
15 value.0.into()
16 }
17 }
18
19 impl From<$ident> for $crate::Token {
20 fn from(value: $ident) -> Self {
21 value.0.into()
22 }
23 }
24
25 impl $crate::ToSpan for $ident {
26 fn to_span(&self) -> Span {
27 self.0.to_span()
28 }
29 }
30
31 impl $crate::SemanticEq for $ident {
32 fn semantic_eq(&self, s: &Self) -> bool {
33 self.0.semantic_eq(&s.0)
34 }
35 }
36 };
37}
38
39macro_rules! define_kind_common {
42 ($(#[$meta:meta])* $ident:ident) => {
43 $(#[$meta])*
44 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
45 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
46 pub struct $ident($crate::Cursor);
47
48 impl $ident {
49 pub const fn dummy() -> Self {
50 Self($crate::Cursor::dummy($crate::Token::dummy($crate::Kind::$ident)))
51 }
52
53 pub fn associated_whitespace(&self) -> $crate::AssociatedWhitespaceRules {
54 self.0.token().associated_whitespace()
55 }
56
57 pub fn with_associated_whitespace(&self, rules: $crate::AssociatedWhitespaceRules) -> Self {
58 Self(self.0.with_associated_whitespace(rules))
59 }
60 }
61
62 impl $crate::ToCursors for $ident {
63 fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
64 s.append((*self).into());
65 }
66 }
67
68 impl<'a> $crate::Peek<'a> for $ident {
69 const PEEK_KINDSET: $crate::KindSet = $crate::KindSet::new(&[$crate::Kind::$ident]);
70 }
71
72 impl<'a> $crate::Parse<'a> for $ident {
73 fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
74 where
75 I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
76 {
77 let c = p.next();
78 if Self::peek(p, c) { Ok(Self(c)) } else { Err($crate::Diagnostic::new(c, $crate::Diagnostic::unexpected))? }
79 }
80 }
81
82
83 impl From<$ident> for $crate::Cursor {
84 fn from(value: $ident) -> Self {
85 value.0.into()
86 }
87 }
88
89 impl From<$ident> for $crate::Token {
90 fn from(value: $ident) -> Self {
91 value.0.into()
92 }
93 }
94
95 impl $crate::ToSpan for $ident {
96 fn to_span(&self) -> $crate::Span {
97 self.0.to_span()
98 }
99 }
100 };
101}
102
103macro_rules! define_kinds {
104 ($($(#[$meta:meta])* $ident:ident,)*) => {
105 $(
106 define_kind_common!($(#[$meta])* $ident);
107
108 impl $crate::SemanticEq for $ident {
109 fn semantic_eq(&self, s: &Self) -> bool {
110 self.0.semantic_eq(&s.0)
111 }
112 }
113 )*
114 };
115}
116
117macro_rules! define_fixed_kinds {
123 ($($(#[$meta:meta])* $ident:ident,)*) => {
124 $(
125 define_kind_common!($(#[$meta])* $ident);
126
127 impl $crate::SemanticEq for $ident {
128 #[inline(always)]
129 fn semantic_eq(&self, _: &Self) -> bool {
130 true
131 }
132 }
133 )*
134 };
135}
136
137macro_rules! define_kind_idents {
138 ($($(#[$meta:meta])* $ident:ident,)*) => {
139 $(
140 $(#[$meta])*
141 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
142 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
143 pub struct $ident($crate::Cursor);
144
145 impl $crate::ToCursors for $ident {
146 fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
147 s.append((*self).into());
148 }
149 }
150
151 impl<'a> $crate::Peek<'a> for $ident {
152 const PEEK_KINDSET: $crate::KindSet = $crate::KindSet::new(&[$crate::Kind::$ident]);
153 }
154
155 impl<'a> $crate::Parse<'a> for $ident {
156 fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
157 where
158 I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
159 {
160 let c = p.next();
161 if Self::peek(p, c) { Ok(Self(c)) } else { Err($crate::Diagnostic::new(c, $crate::Diagnostic::unexpected))? }
162 }
163 }
164
165
166 impl From<$ident> for $crate::Kind {
167 fn from(value: $ident) -> Self {
168 value.0.into()
169 }
170 }
171
172 impl From<$ident> for $crate::Cursor {
173 fn from(value: $ident) -> Self {
174 value.0
175 }
176 }
177
178 impl From<$ident> for $crate::Token {
179 fn from(value: $ident) -> Self {
180 value.0.into()
181 }
182 }
183
184 impl $crate::ToSpan for $ident {
185 fn to_span(&self) -> $crate::Span {
186 self.0.to_span()
187 }
188 }
189
190 impl $crate::SemanticEq for $ident {
191 fn semantic_eq(&self, s: &Self) -> bool {
192 self.0.semantic_eq(&s.0)
193 }
194 }
195
196 impl $ident {
197 pub fn is_dashed_ident(&self) -> bool {
199 self.0.token().is_dashed_ident()
200 }
201
202 pub const fn dummy() -> Self {
203 Self($crate::Cursor::dummy($crate::Token::dummy($crate::Kind::$ident)))
204 }
205 }
206 )*
207 };
208}
209
210#[macro_export]
224macro_rules! custom_delim {
225 ($(#[$meta:meta])* $ident:ident, $ch:literal) => {
226 $(#[$meta])*
227 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
228 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
229 pub struct $ident($crate::T![Delim]);
230
231 impl $ident {
232 pub fn associated_whitespace(&self) -> $crate::AssociatedWhitespaceRules {
233 self.0.associated_whitespace()
234 }
235
236 pub fn with_associated_whitespace(&self, rules: $crate::AssociatedWhitespaceRules) -> Self {
237 Self(self.0.with_associated_whitespace(rules))
238 }
239 }
240
241 impl $crate::ToCursors for $ident {
242 fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
243 s.append((*self).into());
244 }
245 }
246
247 impl<'a> $crate::Peek<'a> for $ident {
248 fn peek<I>(_: &$crate::Parser<'a, I>, c: $crate::Cursor) -> bool
249 where
250 I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
251 {
252 c == $crate::Kind::Delim && c == $ch
253 }
254 }
255
256 impl<'a> $crate::Parse<'a> for $ident {
257 fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
258 where
259 I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
260 {
261 use $crate::Peek;
262 let delim = p.parse::<$crate::T![Delim]>()?;
263 if Self::peek(p, delim.into()) {
264 Ok(Self(delim))
265 } else {
266 Err($crate::Diagnostic::new(delim.into(), $crate::Diagnostic::unexpected))?
267 }
268 }
269 }
270
271
272
273 impl From<$ident> for $crate::Cursor {
274 fn from(value: $ident) -> Self {
275 value.0.into()
276 }
277 }
278
279 impl $crate::ToSpan for $ident {
280 fn to_span(&self) -> $crate::Span {
281 self.0.to_span()
282 }
283 }
284
285 impl PartialEq<char> for $ident {
286 fn eq(&self, other: &char) -> bool {
287 self.0 == *other
288 }
289 }
290
291 impl $crate::SemanticEq for $ident {
292 #[inline(always)]
293 fn semantic_eq(&self, _: &Self) -> bool {
294 true
297 }
298 }
299 };
300}
301
302#[macro_export]
317macro_rules! custom_double_delim {
318 ($(#[$meta:meta])*$ident: ident, $first: literal, $second: literal) => {
319 $(#[$meta])*
320 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
321 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
322 pub struct $ident($crate::T![Delim], pub $crate::T![Delim]);
323
324 impl $ident {
325 pub const fn dummy() -> Self {
326 Self(<$crate::T![Delim]>::dummy(), <$crate::T![Delim]>::dummy())
327 }
328 }
329
330 impl<'a> $crate::Peek<'a> for $ident {
331 fn peek<I>(p: &$crate::Parser<'a, I>, c: $crate::Cursor) -> bool
332 where
333 I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
334 {
335 c == $first && p.peek_n(2) == $second
336 }
337 }
338
339 impl<'a> $crate::Parse<'a> for $ident {
340 fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
341 where
342 I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
343 {
344 let first = p.parse::<$crate::T![Delim]>()?;
345 if first != $first {
346 let c: Cursor = first.into();
347 Err($crate::Diagnostic::new(c, $crate::Diagnostic::expected_delim))?;
348 }
349 let skip = p.set_skip($crate::KindSet::NONE);
350 let second = p.parse::<$crate::T![Delim]>();
351 p.set_skip(skip);
352 let second = second?;
353 if second != $second {
354 let c:Cursor = second.into();
355 Err($crate::Diagnostic::new(c, $crate::Diagnostic::expected_delim))?;
356 }
357 Ok(Self(first, second))
358 }
359 }
360
361 impl<'a> $crate::ToCursors for $ident {
362 fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
363 s.append(self.0.into());
364 s.append(self.1.into());
365 }
366 }
367
368 impl $crate::ToSpan for $ident {
369 fn to_span(&self) -> $crate::Span {
370 self.0.to_span() + self.1.to_span()
371 }
372 }
373
374 impl $crate::SemanticEq for $ident {
375 #[inline(always)]
376 fn semantic_eq(&self, _: &Self) -> bool {
377 true
380 }
381 }
382 };
383}
384
385define_kinds! {
386 Eof,
388
389 Comment,
391
392 CdcOrCdo,
394
395 BadString,
397
398 BadUrl,
400
401 Delim,
403}
404
405define_fixed_kinds! {
406 Colon,
408
409 Semicolon,
411
412 Comma,
414
415 LeftCurly,
417
418 RightCurly,
420
421 LeftSquare,
423
424 RightSquare,
426
427 LeftParen,
429
430 RightParen,
432}
433
434impl PartialEq<char> for Delim {
435 fn eq(&self, other: &char) -> bool {
436 self.0 == *other
437 }
438}
439
440define_kind_idents! {
441 Ident,
443
444 String,
446
447 Url,
449
450 Function,
452
453 AtKeyword,
455
456 Hash,
458}
459
460#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
463#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
464pub struct Whitespace(Cursor);
465cursor_wrapped!(Whitespace);
466
467impl<'a> Peek<'a> for Whitespace {
468 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Whitespace]);
469
470 fn peek<I>(p: &Parser<'a, I>, _: Cursor) -> bool
471 where
472 I: Iterator<Item = Cursor> + Clone,
473 {
474 let c = p.peek_n_with_skip(1, KindSet::COMMENTS);
476 c == Kind::Whitespace
477 }
478}
479
480impl<'a> Parse<'a> for Whitespace {
481 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
482 where
483 I: Iterator<Item = Cursor> + Clone,
484 {
485 let skip = p.set_skip(KindSet::COMMENTS);
488 let c = p.next();
489 p.set_skip(skip);
490 if c != Kind::Whitespace {
491 Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))?
492 }
493 Ok(Self(c))
494 }
495}
496
497#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
500#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
501pub struct DashedIdent(Ident);
502cursor_wrapped!(DashedIdent);
503
504impl<'a> Peek<'a> for DashedIdent {
505 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Ident]);
506
507 #[inline(always)]
508 fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
509 where
510 I: Iterator<Item = Cursor> + Clone,
511 {
512 c == Kind::Ident && c.token().is_dashed_ident()
513 }
514}
515
516impl<'a> Parse<'a> for DashedIdent {
517 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
518 where
519 I: Iterator<Item = Cursor> + Clone,
520 {
521 let c = p.next();
522 if Self::peek(p, c) {
523 Ok(Self(Ident(c)))
524 } else {
525 Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))?
526 }
527 }
528}
529
530#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
532#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
533pub struct Dimension(Cursor);
534cursor_wrapped!(Dimension);
535
536impl PartialEq<f32> for Dimension {
537 fn eq(&self, other: &f32) -> bool {
538 self.0.token().value() == *other
539 }
540}
541
542impl<'a> Peek<'a> for Dimension {
543 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Dimension]);
544}
545
546impl<'a> Parse<'a> for Dimension {
547 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
548 where
549 I: Iterator<Item = Cursor> + Clone,
550 {
551 let c = p.next();
552 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
553 }
554}
555
556impl From<Dimension> for f32 {
557 fn from(val: Dimension) -> Self {
558 val.0.token().value()
559 }
560}
561
562impl ToNumberValue for Dimension {
563 fn to_number_value(&self) -> Option<f32> {
564 Some(self.0.token().value())
565 }
566}
567
568impl Dimension {
569 pub fn value(&self) -> f32 {
571 self.0.token().value()
572 }
573}
574
575#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
577#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
578pub struct Number(Cursor);
579cursor_wrapped!(Number);
580
581impl Number {
582 pub const NUMBER_ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
583 pub const ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
584
585 pub fn value(&self) -> f32 {
587 self.0.token().value()
588 }
589
590 pub fn is_int(&self) -> bool {
591 self.0.token().is_int()
592 }
593
594 pub fn is_float(&self) -> bool {
595 self.0.token().is_float()
596 }
597
598 pub fn has_sign(&self) -> bool {
599 self.0.token().has_sign()
600 }
601
602 pub fn preserve_sign(self) -> Self {
603 if self.has_sign() { Self(self.0.with_sign_required()) } else { self }
604 }
605}
606
607impl<'a> Peek<'a> for Number {
608 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Number]);
609}
610
611impl<'a> Parse<'a> for Number {
612 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
613 where
614 I: Iterator<Item = Cursor> + Clone,
615 {
616 let c = p.next();
617 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
618 }
619}
620
621impl From<Number> for f32 {
622 fn from(value: Number) -> Self {
623 value.value()
624 }
625}
626
627impl From<Number> for i32 {
628 fn from(value: Number) -> Self {
629 value.value() as i32
630 }
631}
632
633impl PartialEq<f32> for Number {
634 fn eq(&self, other: &f32) -> bool {
635 self.value() == *other
636 }
637}
638
639impl ToNumberValue for Number {
640 fn to_number_value(&self) -> Option<f32> {
641 Some(self.value())
642 }
643}
644
645impl ToNormalisedValue for Number {
646 fn to_normalised_value(&self) -> Option<f32> {
647 self.to_number_value()
648 }
649}
650
651pub mod delim {
653 custom_delim! {
654 And, '&'
657 }
658 custom_delim! {
659 At, '@'
663 }
664 custom_delim! {
665 Caret, '^'
668 }
669 custom_delim! {
670 Dash, '-'
673 }
674 custom_delim! {
675 Dollar, '$'
678 }
679 custom_delim! {
680 Dot, '.'
683 }
684 custom_delim! {
685 Eq, '='
688 }
689 custom_delim! {
690 Gt, '>'
693 }
694 custom_delim! {
695 Hash, '#'
699 }
700 custom_delim! {
701 Lt, '<'
704 }
705 custom_delim! {
706 Bang, '!'
709 }
710 custom_delim! {
711 Or, '|'
714 }
715 custom_delim! {
716 Percent, '%'
719 }
720 custom_delim! {
721 Plus, '+'
724 }
725 custom_delim! {
726 Question, '?'
729 }
730 custom_delim! {
731 Slash, '/'
734 }
735 custom_delim! {
736 Star, '*'
739 }
740 custom_delim! {
741 Tilde, '~'
744 }
745 custom_delim! {
746 Underscore, '_'
749 }
750 custom_delim! {
751 Backtick, '`'
754 }
755}
756
757pub mod double {
761 use crate::{
762 Cursor, CursorSink, Kind, KindSet, Parse, Parser, Peek, Result, SemanticEq, Span, T, ToCursors, ToSpan,
763 };
764
765 custom_double_delim! {
766 GreaterThanEqual, '>', '='
770 }
771 custom_double_delim! {
772 LessThanEqual, '<', '='
776 }
777 custom_double_delim! {
778 StarPipe, '*', '|'
782 }
783 custom_double_delim! {
784 PipePipe, '|', '|'
788 }
789 custom_double_delim! {
790 EqualEqual, '=', '='
794 }
795 custom_double_delim! {
796 TildeEqual, '~', '='
800 }
801 custom_double_delim! {
802 PipeEqual, '|', '='
806 }
807 custom_double_delim! {
808 CaretEqual, '^', '='
812 }
813 custom_double_delim! {
814 DollarEqual, '$', '='
818 }
819 custom_double_delim! {
820 StarEqual, '*', '='
824 }
825 custom_double_delim! {
826 BangEqual, '*', '='
830 }
831
832 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
835 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
836 pub struct ColonColon(T![:], T![:]);
837
838 impl ColonColon {
839 pub const fn dummy() -> Self {
840 Self(<T![:]>::dummy(), <T![:]>::dummy())
841 }
842 }
843
844 impl<'a> Peek<'a> for ColonColon {
845 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
846 where
847 I: Iterator<Item = Cursor> + Clone,
848 {
849 c == Kind::Colon && p.peek_n(2) == Kind::Colon
850 }
851 }
852
853 impl<'a> Parse<'a> for ColonColon {
854 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
855 where
856 I: Iterator<Item = Cursor> + Clone,
857 {
858 let first = p.parse::<T![:]>()?;
859 let skip = p.set_skip(KindSet::NONE);
860 let second = p.parse::<T![:]>();
861 p.set_skip(skip);
862 Ok(Self(first, second?))
863 }
864 }
865
866 impl ToCursors for ColonColon {
867 fn to_cursors(&self, s: &mut impl CursorSink) {
868 s.append(self.0.into());
869 s.append(self.1.into());
870 }
871 }
872
873 impl ToSpan for ColonColon {
874 fn to_span(&self) -> Span {
875 self.0.to_span() + self.1.to_span()
876 }
877 }
878
879 impl SemanticEq for ColonColon {
880 #[inline(always)]
881 fn semantic_eq(&self, _: &Self) -> bool {
882 true
885 }
886 }
887}
888
889#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
891#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
892pub struct Any(Cursor);
893cursor_wrapped!(Any);
894
895impl<'a> Peek<'a> for Any {
896 fn peek<I>(_: &Parser<'a, I>, _: Cursor) -> bool
897 where
898 I: Iterator<Item = Cursor> + Clone,
899 {
900 true
901 }
902}
903
904impl<'a> Parse<'a> for Any {
905 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
906 where
907 I: Iterator<Item = Cursor> + Clone,
908 {
909 let c = p.next();
910 Ok(Self(c))
911 }
912}
913
914#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
917#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
918pub struct PairWiseStart(Cursor);
919cursor_wrapped!(PairWiseStart);
920
921impl PairWiseStart {
922 pub fn kind(&self) -> Kind {
923 self.0.token().kind()
924 }
925
926 pub fn end(&self) -> Kind {
927 match self.kind() {
928 Kind::LeftCurly => Kind::RightCurly,
929 Kind::LeftParen => Kind::RightParen,
930 Kind::LeftSquare => Kind::RightSquare,
931 k => k,
932 }
933 }
934}
935
936impl<'a> Peek<'a> for PairWiseStart {
937 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::LeftSquare, Kind::LeftParen]);
938}
939
940impl<'a> Parse<'a> for PairWiseStart {
941 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
942 where
943 I: Iterator<Item = Cursor> + Clone,
944 {
945 let c = p.next();
946 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
947 }
948}
949
950#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
953#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
954pub struct PairWiseEnd(Cursor);
955cursor_wrapped!(PairWiseEnd);
956
957impl PairWiseEnd {
958 pub fn kind(&self) -> Kind {
959 self.0.token().kind()
960 }
961
962 pub fn start(&self) -> Kind {
963 match self.kind() {
964 Kind::RightCurly => Kind::LeftCurly,
965 Kind::RightParen => Kind::LeftParen,
966 Kind::RightSquare => Kind::LeftSquare,
967 k => k,
968 }
969 }
970}
971
972impl<'a> Peek<'a> for PairWiseEnd {
973 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::RightCurly, Kind::RightSquare, Kind::RightParen]);
974}
975
976impl<'a> Parse<'a> for PairWiseEnd {
977 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
978 where
979 I: Iterator<Item = Cursor> + Clone,
980 {
981 let c = p.next();
982 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
983 }
984}
985
986#[macro_export]
989macro_rules! T {
990 [:] => { $crate::token_macros::Colon };
991 [;] => { $crate::token_macros::Semicolon };
992 [,] => { $crate::token_macros::Comma };
993 ['{'] => { $crate::token_macros::LeftCurly };
994 ['}'] => { $crate::token_macros::RightCurly };
995 ['['] => { $crate::token_macros::LeftSquare };
996 [']'] => { $crate::token_macros::RightSquare };
997 ['('] => { $crate::token_macros::LeftParen };
998 [')'] => { $crate::token_macros::RightParen };
999 [' '] => { $crate::token_macros::Whitespace };
1000
1001 [&] => { $crate::token_macros::delim::And };
1002 [@] => { $crate::token_macros::delim::At };
1003 [^] => { $crate::token_macros::delim::Caret };
1004 [-] => { $crate::token_macros::delim::Dash };
1005 [$] => { $crate::token_macros::delim::Dollar };
1006 [.] => { $crate::token_macros::delim::Dot };
1007 [=] => { $crate::token_macros::delim::Eq };
1008 [>] => { $crate::token_macros::delim::Gt };
1009 [#] => { $crate::token_macros::delim::Hash };
1010 [<] => { $crate::token_macros::delim::Lt };
1011 [!] => { $crate::token_macros::delim::Bang };
1012 [|] => { $crate::token_macros::delim::Or };
1013 [%] => { $crate::token_macros::delim::Percent };
1014 [+] => { $crate::token_macros::delim::Plus };
1015 [?] => { $crate::token_macros::delim::Question };
1016 [/] => { $crate::token_macros::delim::Slash };
1017 [*] => { $crate::token_macros::delim::Star };
1018 [~] => { $crate::token_macros::delim::Tilde };
1019 [_] => { $crate::token_macros::delim::Underscore };
1020 ['`'] => { $crate::token_macros::delim::Backtick };
1021
1022 [>=] => { $crate::token_macros::double::GreaterThanEqual };
1023 [<=] => { $crate::token_macros::double::LessThanEqual };
1024 [*|] => { $crate::token_macros::double::StarPipe };
1025 [::] => { $crate::token_macros::double::ColonColon };
1026 [||] => { $crate::token_macros::double::PipePipe };
1027 [==] => { $crate::token_macros::double::EqualEqual };
1028 [~=] => { $crate::token_macros::double::TildeEqual };
1029 [|=] => { $crate::token_macros::double::PipeEqual };
1030 [^=] => { $crate::token_macros::double::CaretEqual };
1031 ["$="] => { $crate::token_macros::double::DollarEqual };
1032 [*=] => { $crate::token_macros::double::StarEqual };
1033 [!=] => { $crate::token_macros::double::BangEqual };
1034
1035 [Dimension::$ident: ident] => { $crate::token_macros::dimension::$ident };
1036
1037 [!important] => { $crate::token_macros::double::BangImportant };
1038
1039 [$ident:ident] => { $crate::token_macros::$ident }
1040}
1041
1042#[cfg(test)]
1043mod fixed_kind_semantic_eq_tests {
1044 use super::*;
1045 use crate::SemanticEq;
1046 use css_lexer::{AssociatedWhitespaceRules, SourceOffset};
1047
1048 #[test]
1054 fn fixed_punctuation_kinds_are_always_semantic_eq() {
1055 macro_rules! check {
1056 ($ty:ident, $token:expr) => {{
1057 let plain = $ty(Cursor::new(SourceOffset(0), $token));
1058 let with_rule = $ty(Cursor::new(
1059 SourceOffset(0),
1060 $token.with_associated_whitespace(AssociatedWhitespaceRules::EnforceBefore),
1061 ));
1062 assert_ne!(
1063 plain,
1064 with_rule,
1065 "associated whitespace should still affect PartialEq for {}",
1066 stringify!($ty)
1067 );
1068 assert!(
1069 plain.semantic_eq(&with_rule),
1070 "{} should always be semantic_eq regardless of associated whitespace",
1071 stringify!($ty)
1072 );
1073 }};
1074 }
1075 check!(Colon, Token::COLON);
1076 check!(Semicolon, Token::SEMICOLON);
1077 check!(Comma, Token::COMMA);
1078 check!(LeftCurly, Token::LEFT_CURLY);
1079 check!(RightCurly, Token::RIGHT_CURLY);
1080 check!(LeftSquare, Token::LEFT_SQUARE);
1081 check!(RightSquare, Token::RIGHT_SQUARE);
1082 check!(LeftParen, Token::LEFT_PAREN);
1083 check!(RightParen, Token::RIGHT_PAREN);
1084 }
1085}