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.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) -> 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 Whitespace {
468	/// Returns a new [Whitespace] with the significance flag set to `significant`.
469	///
470	/// Whitespace parsed with [Parse] is significant by default: a [Whitespace] in an AST node carries meaning
471	/// (a descendant combinator, or the space in `@charset "utf-8";`) and minifiers must keep it. Set this to
472	/// `false` for whitespace kept only as trivia, which a minifier is free to remove.
473	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		// Whitespace needs to peek its own cursor because it was likely given one that skipped Whitespace.
486		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		// Whitespace needs to implement parse so that it can change the skip-state to only ensuring Whitespace
497		// is not ignored.
498		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/// Represents a token with [Kind::Ident] that also begins with two HYPHEN MINUS (`--`)
509/// characters. Use [T![DashedIdent]][crate::T] to refer to this.
510#[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/// Represents a token with [Kind::Dimension]. Use [T![Dimension]][crate::T] to refer to this.
542#[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	/// Returns the [f32] representation of the dimension's value.
581	pub fn value(&self) -> f32 {
582		self.0.token().value()
583	}
584}
585
586/// Represents a token with [Kind::Number]. Use [T![Number]][crate::T] to refer to this.
587#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
588#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
589pub struct Number(Cursor);
590cursor_wrapped!(Number);
591
592impl Number {
593	pub const NUMBER_ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
594	pub const ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
595
596	/// Returns the [f32] representation of the number's value.
597	pub fn value(&self) -> f32 {
598		self.0.token().value()
599	}
600
601	pub fn is_int(&self) -> bool {
602		self.0.token().is_int()
603	}
604
605	pub fn is_float(&self) -> bool {
606		self.0.token().is_float()
607	}
608
609	pub fn has_sign(&self) -> bool {
610		self.0.token().has_sign()
611	}
612
613	pub fn preserve_sign(self) -> Self {
614		if self.has_sign() { Self(self.0.map_token(|t| t.with_sign_required())) } else { self }
615	}
616}
617
618impl<'a> Peek<'a> for Number {
619	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Number]);
620}
621
622impl<'a> Parse<'a> for Number {
623	fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
624	where
625		I: Iterator<Item = Cursor> + Clone,
626	{
627		let c = p.next();
628		if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
629	}
630}
631
632impl From<Number> for f32 {
633	fn from(value: Number) -> Self {
634		value.value()
635	}
636}
637
638impl From<Number> for i32 {
639	fn from(value: Number) -> Self {
640		value.value() as i32
641	}
642}
643
644impl PartialEq<f32> for Number {
645	fn eq(&self, other: &f32) -> bool {
646		self.value() == *other
647	}
648}
649
650impl ToNumberValue for Number {
651	fn to_number_value(&self) -> Option<f32> {
652		Some(self.value())
653	}
654}
655
656impl ToNormalisedValue for Number {
657	fn to_normalised_value(&self) -> Option<f32> {
658		self.to_number_value()
659	}
660}
661
662/// Various [T!s][crate::T] representing a tokens with [Kind::Delim], but each represents a discrete character.
663pub mod delim {
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		And, '&'
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. Not to be conused with [T![AtKeyword]][crate::T] which represents a token with
672		/// [Kind::AtKeyword][crate::Kind::AtKeyword].
673		At, '@'
674	}
675	custom_delim! {
676		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `^`. Use [T![^]][crate::T] to
677		/// refer to this.
678		Caret, '^'
679	}
680	custom_delim! {
681		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `-`. Use [T![-]][crate::T] to
682		/// refer to this.
683		Dash, '-'
684	}
685	custom_delim! {
686		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `$`. Use [T![$]][crate::T] to
687		/// refer to this.
688		Dollar, '$'
689	}
690	custom_delim! {
691		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `.`. Use [T![.]][crate::T] to
692		/// refer to this.
693		Dot, '.'
694	}
695	custom_delim! {
696		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `=`. Use [T![=]][crate::T] to
697		/// refer to this.
698		Eq, '='
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		Gt, '>'
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. Not to be conused with [T![Hash]][crate::T] which represents a token with
708		/// [Kind::Hash][crate::Kind::Hash].
709		Hash, '#'
710	}
711	custom_delim! {
712		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `<`. Use [T![<]][crate::T] to
713		/// refer to this.
714		Lt, '<'
715	}
716	custom_delim! {
717		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `!`. Use [T![!]][crate::T] to
718		/// refer to this.
719		Bang, '!'
720	}
721	custom_delim! {
722		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `|`. Use [T![|]][crate::T] to
723		/// refer to this.
724		Or, '|'
725	}
726	custom_delim! {
727		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `%`. Use [T![%]][crate::T] to
728		/// refer to this.
729		Percent, '%'
730	}
731	custom_delim! {
732		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `+`. Use [T![+]][crate::T] to
733		/// refer to this.
734		Plus, '+'
735	}
736	custom_delim! {
737		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `?`. Use [T![?]][crate::T] to
738		/// refer to this.
739		Question, '?'
740	}
741	custom_delim! {
742		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `/`. Use [T![/]][crate::T] to
743		/// refer to this.
744		Slash, '/'
745	}
746	custom_delim! {
747		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `*`. Use [T![*]][crate::T] to
748		/// refer to this.
749		Star, '*'
750	}
751	custom_delim! {
752		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `~`. Use [T![~]][crate::T] to
753		/// refer to this.
754		Tilde, '~'
755	}
756	custom_delim! {
757		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char `_`. Use [T![_]][crate::T] to
758		/// refer to this.
759		Underscore, '_'
760	}
761	custom_delim! {
762		/// Represents a token with [Kind::Delim][crate::Kind::Delim] that has the char ```. Use [T!['`']][crate::T] to
763		/// refer to this.
764		Backtick, '`'
765	}
766}
767
768/// Various [T!s][crate::T] representing two consecutive tokens that cannot be separated by any other tokens. These are
769/// convenient as it can be tricky to parse two consecutive tokens given the default behaviour of the parser is to skip
770/// whitespace and comments.
771pub mod double {
772	use crate::{
773		Cursor, CursorSink, Kind, KindSet, Parse, Parser, Peek, Result, SemanticEq, Span, T, ToCursors, ToSpan,
774	};
775
776	custom_double_delim! {
777		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
778		/// other token. The first token has the char `>` while the second has the char `=`, representing `>=`. Use
779		/// [T![>=]][crate::T] to refer to this.
780		GreaterThanEqual, '>', '='
781	}
782	custom_double_delim! {
783		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
784		/// other token. The first token has the char `<` while the second has the char `=`, representing `<=`. Use
785		/// [T![<=]][crate::T] to refer to this.
786		LessThanEqual, '<', '='
787	}
788	custom_double_delim! {
789		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
790		/// other token. The first token has the char `*` while the second has the char `|`, representing `*|`. Use
791		/// [T![*|]][crate::T] to refer to this.
792		StarPipe, '*', '|'
793	}
794	custom_double_delim! {
795		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
796		/// other token. The first token has the char `|` while the second has the char `|`, representing `||`. Use
797		/// [T![||]][crate::T] to refer to this.
798		PipePipe, '|', '|'
799	}
800	custom_double_delim! {
801		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
802		/// other token. The first token has the char `=` while the second has the char `=`, representing `==`. Use
803		/// [T![==]][crate::T] to refer to this.
804		EqualEqual, '=', '='
805	}
806	custom_double_delim! {
807		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
808		/// other token. The first token has the char `~` while the second has the char `=`, representing `~=`. Use
809		/// [T![~=]][crate::T] to refer to this.
810		TildeEqual, '~', '='
811	}
812	custom_double_delim! {
813		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
814		/// other token. The first token has the char `|` while the second has the char `=`, representing `|=`. Use
815		/// [T![|=]][crate::T] to refer to this.
816		PipeEqual, '|', '='
817	}
818	custom_double_delim! {
819		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
820		/// other token. The first token has the char `^` while the second has the char `=`, representing `^=`. Use
821		/// [T![\^=]][crate::T] to refer to this.
822		CaretEqual, '^', '='
823	}
824	custom_double_delim! {
825		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
826		/// other token. The first token has the char `$` while the second has the char `=`, representing `$=`. Use
827		/// [T![$=]][crate::T] to refer to this.
828		DollarEqual, '$', '='
829	}
830	custom_double_delim! {
831		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
832		/// other token. The first token has the char `*` while the second has the char `=`, representing `*=`. Use
833		/// [T![*=]][crate::T] to refer to this.
834		StarEqual, '*', '='
835	}
836	custom_double_delim! {
837		/// Represents a two consecutive tokens with [Kind::Delim][crate::Kind::Delim] that cannot be separated by any
838		/// other token. The first token has the char `!` while the second has the char `=`, representing `!=`. Use
839		/// [T![!=]][crate::T] to refer to this.
840		BangEqual, '*', '='
841	}
842
843	/// Represents a two consecutive tokens with [Kind::Colon] that cannot be separated by any other token, representing
844	/// `::`. Use [T![::]][crate::T] to refer to this.
845	#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
846	#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
847	pub struct ColonColon(T![:], T![:]);
848
849	impl ColonColon {
850		pub const fn dummy() -> Self {
851			Self(<T![:]>::dummy(), <T![:]>::dummy())
852		}
853	}
854
855	impl<'a> Peek<'a> for ColonColon {
856		fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
857		where
858			I: Iterator<Item = Cursor> + Clone,
859		{
860			c == Kind::Colon && p.peek_n(2) == Kind::Colon
861		}
862	}
863
864	impl<'a> Parse<'a> for ColonColon {
865		fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
866		where
867			I: Iterator<Item = Cursor> + Clone,
868		{
869			let first = p.parse::<T![:]>()?;
870			let skip = p.set_skip(KindSet::NONE);
871			let second = p.parse::<T![:]>();
872			p.set_skip(skip);
873			Ok(Self(first, second?))
874		}
875	}
876
877	impl ToCursors for ColonColon {
878		fn to_cursors(&self, s: &mut impl CursorSink) {
879			s.append(self.0.into());
880			s.append(self.1.into());
881		}
882	}
883
884	impl ToSpan for ColonColon {
885		fn to_span(&self) -> Span {
886			self.0.to_span() + self.1.to_span()
887		}
888	}
889
890	impl SemanticEq for ColonColon {
891		#[inline(always)]
892		fn semantic_eq(&self, _: &Self) -> bool {
893			// Both `:` characters are fixed by the type itself, so there is nothing left to
894			// compare.
895			true
896		}
897	}
898}
899
900/// Represents any possible single token. Use [T![Any]][crate::T] to refer to this.
901#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
902#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
903pub struct Any(Cursor);
904cursor_wrapped!(Any);
905
906impl<'a> Peek<'a> for Any {
907	fn peek<I>(_: &Parser<'a, I>, _: Cursor) -> bool
908	where
909		I: Iterator<Item = Cursor> + Clone,
910	{
911		true
912	}
913}
914
915impl<'a> Parse<'a> for Any {
916	fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
917	where
918		I: Iterator<Item = Cursor> + Clone,
919	{
920		let c = p.next();
921		Ok(Self(c))
922	}
923}
924
925/// Represents a token with either [Kind::LeftCurly], [Kind::LeftParen] or [Kind::LeftSquare]. Use
926/// [T![PairWiseStart]][crate::T] to refer to this.
927#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
928#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
929pub struct PairWiseStart(Cursor);
930cursor_wrapped!(PairWiseStart);
931
932impl PairWiseStart {
933	pub fn kind(&self) -> Kind {
934		self.0.token().kind()
935	}
936
937	pub fn end(&self) -> Kind {
938		match self.kind() {
939			Kind::LeftCurly => Kind::RightCurly,
940			Kind::LeftParen => Kind::RightParen,
941			Kind::LeftSquare => Kind::RightSquare,
942			k => k,
943		}
944	}
945}
946
947impl<'a> Peek<'a> for PairWiseStart {
948	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::LeftSquare, Kind::LeftParen]);
949}
950
951impl<'a> Parse<'a> for PairWiseStart {
952	fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
953	where
954		I: Iterator<Item = Cursor> + Clone,
955	{
956		let c = p.next();
957		if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
958	}
959}
960
961/// Represents a token with either [Kind::RightCurly], [Kind::RightParen] or [Kind::RightSquare]. Use
962/// [T![PairWiseEnd]][crate::T] to refer to this.
963#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
964#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
965pub struct PairWiseEnd(Cursor);
966cursor_wrapped!(PairWiseEnd);
967
968impl PairWiseEnd {
969	pub fn kind(&self) -> Kind {
970		self.0.token().kind()
971	}
972
973	pub fn start(&self) -> Kind {
974		match self.kind() {
975			Kind::RightCurly => Kind::LeftCurly,
976			Kind::RightParen => Kind::LeftParen,
977			Kind::RightSquare => Kind::LeftSquare,
978			k => k,
979		}
980	}
981}
982
983impl<'a> Peek<'a> for PairWiseEnd {
984	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::RightCurly, Kind::RightSquare, Kind::RightParen]);
985}
986
987impl<'a> Parse<'a> for PairWiseEnd {
988	fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
989	where
990		I: Iterator<Item = Cursor> + Clone,
991	{
992		let c = p.next();
993		if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
994	}
995}
996
997/// 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
998/// fields to type child nodes.
999#[macro_export]
1000macro_rules! T {
1001	[:] => { $crate::token_macros::Colon };
1002	[;] => { $crate::token_macros::Semicolon };
1003	[,] => { $crate::token_macros::Comma };
1004	['{'] => { $crate::token_macros::LeftCurly };
1005	['}'] => { $crate::token_macros::RightCurly };
1006	['['] => { $crate::token_macros::LeftSquare };
1007	[']'] => { $crate::token_macros::RightSquare };
1008	['('] => { $crate::token_macros::LeftParen };
1009	[')'] => { $crate::token_macros::RightParen };
1010	[' '] => { $crate::token_macros::Whitespace };
1011
1012	[&] => { $crate::token_macros::delim::And };
1013	[@] => { $crate::token_macros::delim::At };
1014	[^] => { $crate::token_macros::delim::Caret };
1015	[-] => { $crate::token_macros::delim::Dash };
1016	[$] => { $crate::token_macros::delim::Dollar };
1017	[.] => { $crate::token_macros::delim::Dot };
1018	[=] => { $crate::token_macros::delim::Eq };
1019	[>] => { $crate::token_macros::delim::Gt };
1020	[#] => { $crate::token_macros::delim::Hash };
1021	[<] => { $crate::token_macros::delim::Lt };
1022	[!] => { $crate::token_macros::delim::Bang };
1023	[|] => { $crate::token_macros::delim::Or };
1024	[%] => { $crate::token_macros::delim::Percent };
1025	[+] => { $crate::token_macros::delim::Plus };
1026	[?] => { $crate::token_macros::delim::Question };
1027	[/] => { $crate::token_macros::delim::Slash };
1028	[*] => { $crate::token_macros::delim::Star };
1029	[~] => { $crate::token_macros::delim::Tilde };
1030	[_] => { $crate::token_macros::delim::Underscore };
1031	['`'] => { $crate::token_macros::delim::Backtick };
1032
1033	[>=] => { $crate::token_macros::double::GreaterThanEqual };
1034	[<=] => { $crate::token_macros::double::LessThanEqual };
1035	[*|] => { $crate::token_macros::double::StarPipe };
1036	[::] => { $crate::token_macros::double::ColonColon };
1037	[||] => { $crate::token_macros::double::PipePipe };
1038	[==] => { $crate::token_macros::double::EqualEqual };
1039	[~=] => { $crate::token_macros::double::TildeEqual };
1040	[|=] => { $crate::token_macros::double::PipeEqual };
1041	[^=] => { $crate::token_macros::double::CaretEqual };
1042	["$="] => { $crate::token_macros::double::DollarEqual };
1043	[*=] => { $crate::token_macros::double::StarEqual };
1044	[!=] => { $crate::token_macros::double::BangEqual };
1045
1046	[Dimension::$ident: ident] => { $crate::token_macros::dimension::$ident };
1047
1048	[!important] => { $crate::token_macros::double::BangImportant };
1049
1050	[$ident:ident] => { $crate::token_macros::$ident }
1051}
1052
1053#[cfg(test)]
1054mod fixed_kind_semantic_eq_tests {
1055	use super::*;
1056	use crate::SemanticEq;
1057	use css_lexer::{AssociatedWhitespaceRules, SourceOffset};
1058
1059	// Colon, Semicolon, Comma, and the paren/curly/square brackets are "delim-like": they
1060	// share Delim's bit layout and can carry non-semantic associated-whitespace formatting
1061	// hints, which makes two otherwise-identical tokens compare unequal via plain `PartialEq`.
1062	// `semantic_eq` must ignore this entirely for these kinds, since there is no other varying
1063	// content once the type is known.
1064	#[test]
1065	fn fixed_punctuation_kinds_are_always_semantic_eq() {
1066		macro_rules! check {
1067			($ty:ident, $token:expr) => {{
1068				let plain = $ty(Cursor::new(SourceOffset(0), $token));
1069				let with_rule = $ty(Cursor::new(
1070					SourceOffset(0),
1071					$token.with_associated_whitespace(AssociatedWhitespaceRules::EnforceBefore),
1072				));
1073				assert_ne!(
1074					plain,
1075					with_rule,
1076					"associated whitespace should still affect PartialEq for {}",
1077					stringify!($ty)
1078				);
1079				assert!(
1080					plain.semantic_eq(&with_rule),
1081					"{} should always be semantic_eq regardless of associated whitespace",
1082					stringify!($ty)
1083				);
1084			}};
1085		}
1086		check!(Colon, Token::COLON);
1087		check!(Semicolon, Token::SEMICOLON);
1088		check!(Comma, Token::COMMA);
1089		check!(LeftCurly, Token::LEFT_CURLY);
1090		check!(RightCurly, Token::RIGHT_CURLY);
1091		check!(LeftSquare, Token::LEFT_SQUARE);
1092		check!(RightSquare, Token::RIGHT_SQUARE);
1093		check!(LeftParen, Token::LEFT_PAREN);
1094		check!(RightParen, Token::RIGHT_PAREN);
1095	}
1096}