Skip to main content

css_parse/
token_macros.rs

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
39/// Shared body for [define_kinds!] and [define_fixed_kinds!]; everything except the
40/// `SemanticEq` impl, which differs between the two (see [define_fixed_kinds!]).
41macro_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
117/// Like [define_kinds!], but for kinds whose content is entirely fixed by the Rust type - once
118/// parsing succeeds there is no varying data left to compare (e.g. a [Comma] is always just a
119/// `,`; the only bits that could otherwise differ are non-semantic associated-whitespace
120/// formatting hints). `semantic_eq` for these kinds is therefore always `true`, skipping the
121/// token comparison outright.
122macro_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			/// Checks if the ident begins with two HYPHEN MINUS (`--`) characters.
198			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/// A macro for defining a struct which captures a [Kind::Delim][Kind::Delim] with a specific character.
211///
212/// # Example
213///
214/// ```
215/// use css_parse::*;
216/// custom_delim!{
217///   /// A £ character.
218///   PoundSterling, '£'
219/// }
220///
221/// assert_parse!(EmptyAtomSet::ATOMS, PoundSterling, "£");
222/// ```
223#[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				// The character is fixed by the type itself (parsing only succeeds for
295				// `$ch`), so there is nothing left to compare.
296				true
297			}
298		}
299	};
300}
301
302/// A macro for defining a struct which captures two adjacent [Kind::Delim][Kind::Delim] tokens, each with a
303/// specific character.
304///
305/// # Example
306///
307/// ```
308/// use css_parse::*;
309/// custom_double_delim!{
310///   /// Two % adjacent symbols
311///   DoublePercent, '%', '%'
312/// }
313///
314/// assert_parse!(EmptyAtomSet::ATOMS, DoublePercent, "%%");
315/// ```
316#[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				// Both characters are fixed by the type itself (`$first` then `$second`), so
378				// there is nothing left to compare.
379				true
380			}
381		}
382	};
383}
384
385define_kinds! {
386	/// Represents a token with [Kind::Eof][Kind::Eof]. Use [T![Eof]][crate::T] to refer to this.
387	Eof,
388
389	/// Represents a token with [Kind::Comment][Kind::Comment]. Use [T![Comment]][crate::T] to refer to this.
390	Comment,
391
392	/// Represents a token with [Kind::CdcOrCdo][Kind::CdcOrCdo]. Use [T![CdcOrCdo]][crate::T] to refer to this.
393	CdcOrCdo,
394
395	/// Represents a token with [Kind::BadString][Kind::BadString]. Use [T![BadString]][crate::T] to refer to this.
396	BadString,
397
398	/// Represents a token with [Kind::BadUrl][Kind::BadUrl]. Use [T![BadUrl]][crate::T] to refer to this.[
399	BadUrl,
400
401	/// Represents a token with [Kind::Delim][Kind::Delim], can be any single character. Use [T![Delim]][crate::T] to refer to this.
402	Delim,
403}
404
405define_fixed_kinds! {
406	/// Represents a token with [Kind::Colon][Kind::Colon] - a `:` character. Use [T![:]][crate::T] to refer to this.
407	Colon,
408
409	/// Represents a token with [Kind::Semicolon][Kind::Semicolon] - a `;` character. Use [T![;]][crate::T] to refer to this.
410	Semicolon,
411
412	/// Represents a token with [Kind::Comma][Kind::Comma] - a `,` character. Use [T![,]][crate::T] to refer to this.
413	Comma,
414
415	/// Represents a token with [Kind::LeftCurly][Kind::LeftCurly] - a `{` character. Use [T!['{']][crate::T] to refer to this.
416	LeftCurly,
417
418	/// Represents a token with [Kind::LeftCurly][Kind::LeftCurly] - a `}` character. Use [T!['}']][crate::T] to refer to this.
419	RightCurly,
420
421	/// Represents a token with [Kind::LeftSquare][Kind::LeftSquare] - a `[` character. Use [T!['[']][crate::T] to refer to this.
422	LeftSquare,
423
424	/// Represents a token with [Kind::RightSquare][Kind::RightSquare] - a `]` character. Use [T![']']][crate::T] to refer to this.
425	RightSquare,
426
427	/// Represents a token with [Kind::LeftParen][Kind::LeftParen] - a `(` character. Use [T!['(']][crate::T] to refer to this.
428	LeftParen,
429
430	/// Represents a token with [Kind::RightParen][Kind::RightParen] - a `(` character. Use [T![')']][crate::T] to refer to this.
431	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	/// Represents a token with [Kind::Ident][Kind::Ident]. Use [T![Ident]][crate::T] to refer to this.
442	Ident,
443
444	/// Represents a token with [Kind::String][Kind::String]. Use [T![String]][crate::T] to refer to this.
445	String,
446
447	/// Represents a token with [Kind::Url][Kind::Url]. Use [T![Url]][crate::T] to refer to this.
448	Url,
449
450	/// Represents a token with [Kind::Function][Kind::Function]. Use [T![Function]][crate::T] to refer to this.
451	Function,
452
453	/// Represents a token with [Kind::AtKeyword][Kind::AtKeyword]. Use [T![AtKeyword]][crate::T] to refer to this.
454	AtKeyword,
455
456	/// Represents a token with [Kind::Hash][Kind::Hash]. Use [T![Hash]][crate::T] to refer to this.
457	Hash,
458}
459
460/// Represents a token with [Kind::Whitespace]. Use [T![Whitespace]][crate::T] to refer to
461/// this.
462#[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		// Whitespace needs to peek its own cursor because it was likely given one that skipped Whitespace.
475		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		// Whitespace needs to implement parse so that it can change the skip-state to only ensuring Whitespace
486		// is not ignored.
487		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/// Represents a token with [Kind::Ident] that also begins with two HYPHEN MINUS (`--`)
498/// characters. Use [T![DashedIdent]][crate::T] to refer to this.
499#[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/// Represents a token with [Kind::Dimension]. Use [T![Dimension]][crate::T] to refer to this.
531#[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	/// Returns the [f32] representation of the dimension's value.
570	pub fn value(&self) -> f32 {
571		self.0.token().value()
572	}
573}
574
575/// Represents a token with [Kind::Number]. Use [T![Number]][crate::T] to refer to this.
576#[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	/// Returns the [f32] representation of the number's value.
586	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
651/// Various [T!s][crate::T] representing a tokens with [Kind::Delim], but each represents a discrete character.
652pub mod delim {
653	custom_delim! {
654		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `&`. Use [T![&]][crate::T] to
655		/// refer to this.
656		And, '&'
657	}
658	custom_delim! {
659		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `@`. Use [T![@]][crate::T] to
660		/// refer to this. Not to be conused with [T![AtKeyword]][crate::T] which represents a token with
661		/// [Kind::AtKeyword][crate::Kind::AtKeyword].
662		At, '@'
663	}
664	custom_delim! {
665		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `^`. Use [T![^]][crate::T] to
666		/// refer to this.
667		Caret, '^'
668	}
669	custom_delim! {
670		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `-`. Use [T![-]][crate::T] to
671		/// refer to this.
672		Dash, '-'
673	}
674	custom_delim! {
675		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `$`. Use [T![$]][crate::T] to
676		/// refer to this.
677		Dollar, '$'
678	}
679	custom_delim! {
680		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `.`. Use [T![.]][crate::T] to
681		/// refer to this.
682		Dot, '.'
683	}
684	custom_delim! {
685		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `=`. Use [T![=]][crate::T] to
686		/// refer to this.
687		Eq, '='
688	}
689	custom_delim! {
690		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `>`. Use [T![>]][crate::T] to
691		/// refer to this.
692		Gt, '>'
693	}
694	custom_delim! {
695		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `#`. Use [T![#]][crate::T] to
696		/// refer to this. Not to be conused with [T![Hash]][crate::T] which represents a token with
697		/// [Kind::Hash][crate::Kind::Hash].
698		Hash, '#'
699	}
700	custom_delim! {
701		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `<`. Use [T![<]][crate::T] to
702		/// refer to this.
703		Lt, '<'
704	}
705	custom_delim! {
706		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `!`. Use [T![!]][crate::T] to
707		/// refer to this.
708		Bang, '!'
709	}
710	custom_delim! {
711		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `|`. Use [T![|]][crate::T] to
712		/// refer to this.
713		Or, '|'
714	}
715	custom_delim! {
716		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `%`. Use [T![%]][crate::T] to
717		/// refer to this.
718		Percent, '%'
719	}
720	custom_delim! {
721		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `+`. Use [T![+]][crate::T] to
722		/// refer to this.
723		Plus, '+'
724	}
725	custom_delim! {
726		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `?`. Use [T![?]][crate::T] to
727		/// refer to this.
728		Question, '?'
729	}
730	custom_delim! {
731		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `/`. Use [T![/]][crate::T] to
732		/// refer to this.
733		Slash, '/'
734	}
735	custom_delim! {
736		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `*`. Use [T![*]][crate::T] to
737		/// refer to this.
738		Star, '*'
739	}
740	custom_delim! {
741		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `~`. Use [T![~]][crate::T] to
742		/// refer to this.
743		Tilde, '~'
744	}
745	custom_delim! {
746		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `_`. Use [T![_]][crate::T] to
747		/// refer to this.
748		Underscore, '_'
749	}
750	custom_delim! {
751		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char ```. Use [T!['`']][crate::T] to
752		/// refer to this.
753		Backtick, '`'
754	}
755}
756
757/// Various [T!s][crate::T] representing two consecutive tokens that cannot be separated by any other tokens. These are
758/// convenient as it can be tricky to parse two consecutive tokens given the default behaviour of the parser is to skip
759/// whitespace and comments.
760pub 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		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
767		/// other token. The first token has the char `>` while the second has the char `=`, representing `>=`. Use
768		/// [T![>=]][crate::T] to refer to this.
769		GreaterThanEqual, '>', '='
770	}
771	custom_double_delim! {
772		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
773		/// other token. The first token has the char `<` while the second has the char `=`, representing `<=`. Use
774		/// [T![<=]][crate::T] to refer to this.
775		LessThanEqual, '<', '='
776	}
777	custom_double_delim! {
778		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
779		/// other token. The first token has the char `*` while the second has the char `|`, representing `*|`. Use
780		/// [T![*|]][crate::T] to refer to this.
781		StarPipe, '*', '|'
782	}
783	custom_double_delim! {
784		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
785		/// other token. The first token has the char `|` while the second has the char `|`, representing `||`. Use
786		/// [T![||]][crate::T] to refer to this.
787		PipePipe, '|', '|'
788	}
789	custom_double_delim! {
790		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
791		/// other token. The first token has the char `=` while the second has the char `=`, representing `==`. Use
792		/// [T![==]][crate::T] to refer to this.
793		EqualEqual, '=', '='
794	}
795	custom_double_delim! {
796		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
797		/// other token. The first token has the char `~` while the second has the char `=`, representing `~=`. Use
798		/// [T![~=]][crate::T] to refer to this.
799		TildeEqual, '~', '='
800	}
801	custom_double_delim! {
802		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
803		/// other token. The first token has the char `|` while the second has the char `=`, representing `|=`. Use
804		/// [T![|=]][crate::T] to refer to this.
805		PipeEqual, '|', '='
806	}
807	custom_double_delim! {
808		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
809		/// other token. The first token has the char `^` while the second has the char `=`, representing `^=`. Use
810		/// [T![\^=]][crate::T] to refer to this.
811		CaretEqual, '^', '='
812	}
813	custom_double_delim! {
814		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
815		/// other token. The first token has the char `$` while the second has the char `=`, representing `$=`. Use
816		/// [T![$=]][crate::T] to refer to this.
817		DollarEqual, '$', '='
818	}
819	custom_double_delim! {
820		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
821		/// other token. The first token has the char `*` while the second has the char `=`, representing `*=`. Use
822		/// [T![*=]][crate::T] to refer to this.
823		StarEqual, '*', '='
824	}
825	custom_double_delim! {
826		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
827		/// other token. The first token has the char `!` while the second has the char `=`, representing `!=`. Use
828		/// [T![!=]][crate::T] to refer to this.
829		BangEqual, '*', '='
830	}
831
832	/// Represents a two consecutive tokens with [Kind::Colon] that cannot be separated by any other token, representing
833	/// `::`. Use [T![::]][crate::T] to refer to this.
834	#[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			// Both `:` characters are fixed by the type itself, so there is nothing left to
883			// compare.
884			true
885		}
886	}
887}
888
889/// Represents any possible single token. Use [T![Any]][crate::T] to refer to this.
890#[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/// Represents a token with either [Kind::LeftCurly], [Kind::LeftParen] or [Kind::LeftSquare]. Use
915/// [T![PairWiseStart]][crate::T] to refer to this.
916#[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/// Represents a token with either [Kind::RightCurly], [Kind::RightParen] or [Kind::RightSquare]. Use
951/// [T![PairWiseEnd]][crate::T] to refer to this.
952#[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/// The [T!][crate::T] macro expands to the name of a type representing the Token of the same name. These can be used in struct
987/// fields to type child nodes.
988#[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	// Colon, Semicolon, Comma, and the paren/curly/square brackets are "delim-like": they
1049	// share Delim's bit layout and can carry non-semantic associated-whitespace formatting
1050	// hints, which makes two otherwise-identical tokens compare unequal via plain `PartialEq`.
1051	// `semantic_eq` must ignore this entirely for these kinds, since there is no other varying
1052	// content once the type is known.
1053	#[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}