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