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, source_text: &str) -> bool {
33 self.0.semantic_eq(&s.0, source_text)
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.map_token(|t| t.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, source_text: &str) -> bool {
110 self.0.semantic_eq(&s.0, source_text)
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, _source_text: &str) -> 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, source_text: &str) -> bool {
192 self.0.semantic_eq(&s.0, source_text)
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, _source_text: &str) -> 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(pub $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, _source_text: &str) -> 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 Whitespace {
468 pub fn with_significant_whitespace(&self, significant: bool) -> Self {
474 Self(self.0.map_token(|t| t.with_significant_whitespace(significant)))
475 }
476}
477
478impl<'a> Peek<'a> for Whitespace {
479 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Whitespace]);
480
481 fn peek<I>(p: &Parser<'a, I>, _: Cursor) -> bool
482 where
483 I: Iterator<Item = Cursor> + Clone,
484 {
485 let c = p.peek_n_with_skip(1, KindSet::COMMENTS);
487 c == Kind::Whitespace
488 }
489}
490
491impl<'a> Parse<'a> for Whitespace {
492 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
493 where
494 I: Iterator<Item = Cursor> + Clone,
495 {
496 let skip = p.set_skip(KindSet::COMMENTS);
499 let c = p.next();
500 p.set_skip(skip);
501 if c != Kind::Whitespace {
502 Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))?
503 }
504 Ok(Self(c.map_token(|t| t.with_significant_whitespace(true))))
505 }
506}
507
508#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
511#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
512pub struct DashedIdent(Ident);
513cursor_wrapped!(DashedIdent);
514
515impl<'a> Peek<'a> for DashedIdent {
516 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Ident]);
517
518 #[inline(always)]
519 fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
520 where
521 I: Iterator<Item = Cursor> + Clone,
522 {
523 c == Kind::Ident && c.token().is_dashed_ident()
524 }
525}
526
527impl<'a> Parse<'a> for DashedIdent {
528 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
529 where
530 I: Iterator<Item = Cursor> + Clone,
531 {
532 let c = p.next();
533 if Self::peek(p, c) {
534 Ok(Self(Ident(c)))
535 } else {
536 Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))?
537 }
538 }
539}
540
541#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
543#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
544pub struct Dimension(Cursor);
545cursor_wrapped!(Dimension);
546
547impl PartialEq<f32> for Dimension {
548 fn eq(&self, other: &f32) -> bool {
549 self.0.token().value() == *other
550 }
551}
552
553impl<'a> Peek<'a> for Dimension {
554 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Dimension]);
555}
556
557impl<'a> Parse<'a> for Dimension {
558 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
559 where
560 I: Iterator<Item = Cursor> + Clone,
561 {
562 let c = p.next();
563 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
564 }
565}
566
567impl From<Dimension> for f32 {
568 fn from(val: Dimension) -> Self {
569 val.0.token().value()
570 }
571}
572
573impl ToNumberValue for Dimension {
574 fn to_number_value(&self) -> Option<f32> {
575 Some(self.0.token().value())
576 }
577}
578
579impl Dimension {
580 pub fn value(&self) -> f32 {
582 self.0.token().value()
583 }
584
585 pub fn preserve_type(self) -> Self {
587 Self(self.0.map_token(|t| t.with_numeric_type_required()))
588 }
589}
590
591#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
593#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
594pub struct Number(Cursor);
595cursor_wrapped!(Number);
596
597impl Number {
598 pub const NUMBER_ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
599 pub const ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
600
601 pub fn value(&self) -> f32 {
603 self.0.token().value()
604 }
605
606 pub fn is_int(&self) -> bool {
607 self.0.token().is_int()
608 }
609
610 pub fn is_float(&self) -> bool {
611 self.0.token().is_float()
612 }
613
614 pub fn has_sign(&self) -> bool {
615 self.0.token().has_sign()
616 }
617
618 pub fn preserve_sign(self) -> Self {
619 if self.has_sign() { Self(self.0.map_token(|t| t.with_sign_required())) } else { self }
620 }
621
622 pub fn preserve_type(self) -> Self {
624 Self(self.0.map_token(|t| t.with_numeric_type_required()))
625 }
626}
627
628impl<'a> Peek<'a> for Number {
629 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Number]);
630}
631
632impl<'a> Parse<'a> for Number {
633 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
634 where
635 I: Iterator<Item = Cursor> + Clone,
636 {
637 let c = p.next();
638 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
639 }
640}
641
642impl From<Number> for f32 {
643 fn from(value: Number) -> Self {
644 value.value()
645 }
646}
647
648impl From<Number> for i32 {
649 fn from(value: Number) -> Self {
650 value.value() as i32
651 }
652}
653
654impl PartialEq<f32> for Number {
655 fn eq(&self, other: &f32) -> bool {
656 self.value() == *other
657 }
658}
659
660impl ToNumberValue for Number {
661 fn to_number_value(&self) -> Option<f32> {
662 Some(self.value())
663 }
664}
665
666impl ToNormalisedValue for Number {
667 fn to_normalised_value(&self) -> Option<f32> {
668 self.to_number_value()
669 }
670}
671
672pub mod delim {
674 custom_delim! {
675 And, '&'
678 }
679 custom_delim! {
680 At, '@'
684 }
685 custom_delim! {
686 Caret, '^'
689 }
690 custom_delim! {
691 Dash, '-'
694 }
695 custom_delim! {
696 Dollar, '$'
699 }
700 custom_delim! {
701 Dot, '.'
704 }
705 custom_delim! {
706 Eq, '='
709 }
710 custom_delim! {
711 Gt, '>'
714 }
715 custom_delim! {
716 Hash, '#'
720 }
721 custom_delim! {
722 Lt, '<'
725 }
726 custom_delim! {
727 Bang, '!'
730 }
731 custom_delim! {
732 Or, '|'
735 }
736 custom_delim! {
737 Percent, '%'
740 }
741 custom_delim! {
742 Plus, '+'
745 }
746 custom_delim! {
747 Question, '?'
750 }
751 custom_delim! {
752 Slash, '/'
755 }
756 custom_delim! {
757 Star, '*'
760 }
761 custom_delim! {
762 Tilde, '~'
765 }
766 custom_delim! {
767 Underscore, '_'
770 }
771 custom_delim! {
772 Backtick, '`'
775 }
776}
777
778pub mod double {
782 use crate::{
783 Cursor, CursorSink, Kind, KindSet, Parse, Parser, Peek, Result, SemanticEq, Span, T, ToCursors, ToSpan,
784 };
785
786 custom_double_delim! {
787 GreaterThanEqual, '>', '='
791 }
792 custom_double_delim! {
793 LessThanEqual, '<', '='
797 }
798 custom_double_delim! {
799 StarPipe, '*', '|'
803 }
804 custom_double_delim! {
805 PipePipe, '|', '|'
809 }
810 custom_double_delim! {
811 EqualEqual, '=', '='
815 }
816 custom_double_delim! {
817 TildeEqual, '~', '='
821 }
822 custom_double_delim! {
823 PipeEqual, '|', '='
827 }
828 custom_double_delim! {
829 CaretEqual, '^', '='
833 }
834 custom_double_delim! {
835 DollarEqual, '$', '='
839 }
840 custom_double_delim! {
841 StarEqual, '*', '='
845 }
846 custom_double_delim! {
847 BangEqual, '*', '='
851 }
852
853 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
856 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
857 pub struct ColonColon(T![:], T![:]);
858
859 impl ColonColon {
860 pub const fn dummy() -> Self {
861 Self(<T![:]>::dummy(), <T![:]>::dummy())
862 }
863 }
864
865 impl<'a> Peek<'a> for ColonColon {
866 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
867 where
868 I: Iterator<Item = Cursor> + Clone,
869 {
870 c == Kind::Colon && p.peek_n(2) == Kind::Colon
871 }
872 }
873
874 impl<'a> Parse<'a> for ColonColon {
875 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
876 where
877 I: Iterator<Item = Cursor> + Clone,
878 {
879 let first = p.parse::<T![:]>()?;
880 let skip = p.set_skip(KindSet::NONE);
881 let second = p.parse::<T![:]>();
882 p.set_skip(skip);
883 Ok(Self(first, second?))
884 }
885 }
886
887 impl ToCursors for ColonColon {
888 fn to_cursors(&self, s: &mut impl CursorSink) {
889 s.append(self.0.into());
890 s.append(self.1.into());
891 }
892 }
893
894 impl ToSpan for ColonColon {
895 fn to_span(&self) -> Span {
896 self.0.to_span() + self.1.to_span()
897 }
898 }
899
900 impl SemanticEq for ColonColon {
901 #[inline(always)]
902 fn semantic_eq(&self, _: &Self, _source_text: &str) -> bool {
903 true
906 }
907 }
908}
909
910#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
912#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
913pub struct Any(Cursor);
914cursor_wrapped!(Any);
915
916impl<'a> Peek<'a> for Any {
917 fn peek<I>(_: &Parser<'a, I>, _: Cursor) -> bool
918 where
919 I: Iterator<Item = Cursor> + Clone,
920 {
921 true
922 }
923}
924
925impl<'a> Parse<'a> for Any {
926 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
927 where
928 I: Iterator<Item = Cursor> + Clone,
929 {
930 let c = p.next();
931 Ok(Self(c))
932 }
933}
934
935#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
938#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
939pub struct PairWiseStart(Cursor);
940cursor_wrapped!(PairWiseStart);
941
942impl PairWiseStart {
943 pub fn kind(&self) -> Kind {
944 self.0.token().kind()
945 }
946
947 pub fn end(&self) -> Kind {
948 match self.kind() {
949 Kind::LeftCurly => Kind::RightCurly,
950 Kind::LeftParen => Kind::RightParen,
951 Kind::LeftSquare => Kind::RightSquare,
952 k => k,
953 }
954 }
955}
956
957impl<'a> Peek<'a> for PairWiseStart {
958 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::LeftSquare, Kind::LeftParen]);
959}
960
961impl<'a> Parse<'a> for PairWiseStart {
962 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
963 where
964 I: Iterator<Item = Cursor> + Clone,
965 {
966 let c = p.next();
967 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
968 }
969}
970
971#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
974#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
975pub struct PairWiseEnd(Cursor);
976cursor_wrapped!(PairWiseEnd);
977
978impl PairWiseEnd {
979 pub fn kind(&self) -> Kind {
980 self.0.token().kind()
981 }
982
983 pub fn start(&self) -> Kind {
984 match self.kind() {
985 Kind::RightCurly => Kind::LeftCurly,
986 Kind::RightParen => Kind::LeftParen,
987 Kind::RightSquare => Kind::LeftSquare,
988 k => k,
989 }
990 }
991}
992
993impl<'a> Peek<'a> for PairWiseEnd {
994 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::RightCurly, Kind::RightSquare, Kind::RightParen]);
995}
996
997impl<'a> Parse<'a> for PairWiseEnd {
998 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
999 where
1000 I: Iterator<Item = Cursor> + Clone,
1001 {
1002 let c = p.next();
1003 if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
1004 }
1005}
1006
1007#[macro_export]
1010macro_rules! T {
1011 [:] => { $crate::token_macros::Colon };
1012 [;] => { $crate::token_macros::Semicolon };
1013 [,] => { $crate::token_macros::Comma };
1014 ['{'] => { $crate::token_macros::LeftCurly };
1015 ['}'] => { $crate::token_macros::RightCurly };
1016 ['['] => { $crate::token_macros::LeftSquare };
1017 [']'] => { $crate::token_macros::RightSquare };
1018 ['('] => { $crate::token_macros::LeftParen };
1019 [')'] => { $crate::token_macros::RightParen };
1020 [' '] => { $crate::token_macros::Whitespace };
1021
1022 [&] => { $crate::token_macros::delim::And };
1023 [@] => { $crate::token_macros::delim::At };
1024 [^] => { $crate::token_macros::delim::Caret };
1025 [-] => { $crate::token_macros::delim::Dash };
1026 [$] => { $crate::token_macros::delim::Dollar };
1027 [.] => { $crate::token_macros::delim::Dot };
1028 [=] => { $crate::token_macros::delim::Eq };
1029 [>] => { $crate::token_macros::delim::Gt };
1030 [#] => { $crate::token_macros::delim::Hash };
1031 [<] => { $crate::token_macros::delim::Lt };
1032 [!] => { $crate::token_macros::delim::Bang };
1033 [|] => { $crate::token_macros::delim::Or };
1034 [%] => { $crate::token_macros::delim::Percent };
1035 [+] => { $crate::token_macros::delim::Plus };
1036 [?] => { $crate::token_macros::delim::Question };
1037 [/] => { $crate::token_macros::delim::Slash };
1038 [*] => { $crate::token_macros::delim::Star };
1039 [~] => { $crate::token_macros::delim::Tilde };
1040 [_] => { $crate::token_macros::delim::Underscore };
1041 ['`'] => { $crate::token_macros::delim::Backtick };
1042
1043 [>=] => { $crate::token_macros::double::GreaterThanEqual };
1044 [<=] => { $crate::token_macros::double::LessThanEqual };
1045 [*|] => { $crate::token_macros::double::StarPipe };
1046 [::] => { $crate::token_macros::double::ColonColon };
1047 [||] => { $crate::token_macros::double::PipePipe };
1048 [==] => { $crate::token_macros::double::EqualEqual };
1049 [~=] => { $crate::token_macros::double::TildeEqual };
1050 [|=] => { $crate::token_macros::double::PipeEqual };
1051 [^=] => { $crate::token_macros::double::CaretEqual };
1052 ["$="] => { $crate::token_macros::double::DollarEqual };
1053 [*=] => { $crate::token_macros::double::StarEqual };
1054 [!=] => { $crate::token_macros::double::BangEqual };
1055
1056 [Dimension::$ident: ident] => { $crate::token_macros::dimension::$ident };
1057
1058 [!important] => { $crate::token_macros::double::BangImportant };
1059
1060 [$ident:ident] => { $crate::token_macros::$ident }
1061}
1062
1063#[cfg(test)]
1064mod fixed_kind_semantic_eq_tests {
1065 use super::*;
1066 use crate::SemanticEq;
1067 use css_lexer::{AssociatedWhitespaceRules, SourceOffset};
1068
1069 #[test]
1075 fn fixed_punctuation_kinds_are_always_semantic_eq() {
1076 macro_rules! check {
1077 ($ty:ident, $token:expr) => {{
1078 let plain = $ty(Cursor::new(SourceOffset(0), $token));
1079 let with_rule = $ty(Cursor::new(
1080 SourceOffset(0),
1081 $token.with_associated_whitespace(AssociatedWhitespaceRules::EnforceBefore),
1082 ));
1083 assert_ne!(
1084 plain,
1085 with_rule,
1086 "associated whitespace should still affect PartialEq for {}",
1087 stringify!($ty)
1088 );
1089 assert!(
1090 plain.semantic_eq(&with_rule, ""),
1091 "{} should always be semantic_eq regardless of associated whitespace",
1092 stringify!($ty)
1093 );
1094 }};
1095 }
1096 check!(Colon, Token::COLON);
1097 check!(Semicolon, Token::SEMICOLON);
1098 check!(Comma, Token::COMMA);
1099 check!(LeftCurly, Token::LEFT_CURLY);
1100 check!(RightCurly, Token::RIGHT_CURLY);
1101 check!(LeftSquare, Token::LEFT_SQUARE);
1102 check!(RightSquare, Token::RIGHT_SQUARE);
1103 check!(LeftParen, Token::LEFT_PAREN);
1104 check!(RightParen, Token::RIGHT_PAREN);
1105 }
1106}