Skip to main content

css_parse/syntax/
bang_important.rs

1use crate::{
2	Cursor, CursorSink, Diagnostic, Kind, KindSet, Parse, Parser, Peek, Result, SemanticEq, Span, T, ToCursors, ToSpan,
3};
4
5/// Represents a two tokens, the first being [Kind::Delim] where the char is `!`, and the second being an `Ident` with
6/// the value `important`. [CSS defines this as]:
7///
8/// ```md
9/// <ws*>
10///     ╭──────────────────────────╮
11///  │├─╯─╭─ <whitespace-token> ─╮─╰─┤│
12///       ╰──────────────────────╯
13///
14/// <!important>
15///  │├─ "!" ─ <ws*> ─ <ident-token "important"> ─ <ws*> ─┤│
16/// ```
17///
18/// `<ws*>` is any number of `<whitespace-token>`s, defined as [Kind::Whitespace][Kind::Whitespace]. This is
19/// automatically skipped by default in the [Parser] anyway.
20///
21/// [1]: https://drafts.csswg.org/css-syntax-3/#!important-diagram
22///
23#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
25pub struct BangImportant {
26	pub bang: T![!],
27	pub important: T![Ident],
28}
29
30impl<'a> Peek<'a> for BangImportant {
31	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Delim]);
32
33	#[inline(always)]
34	fn peek<Iter>(p: &Parser<'a, Iter>, c: Cursor) -> bool
35	where
36		Iter: Iterator<Item = Cursor> + Clone,
37	{
38		if c == Kind::Delim && c == '!' {
39			let c = p.peek_n(2);
40			c == Kind::Ident && p.to_source_cursor(c).eq_ignore_ascii_case("important")
41		} else {
42			false
43		}
44	}
45}
46
47impl<'a> Parse<'a> for BangImportant {
48	fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self>
49	where
50		Iter: Iterator<Item = Cursor> + Clone,
51	{
52		let bang = p.parse::<T![!]>()?;
53		let important = p.parse::<T![Ident]>()?;
54		if !p.to_source_cursor(important.into()).eq_ignore_ascii_case("important") {
55			Err(Diagnostic::new(important.into(), Diagnostic::unexpected_ident))?
56		}
57		Ok(Self { bang, important })
58	}
59}
60
61impl ToCursors for BangImportant {
62	fn to_cursors(&self, s: &mut impl CursorSink) {
63		s.append(self.bang.into());
64		s.append(self.important.into());
65	}
66}
67
68impl ToSpan for BangImportant {
69	fn to_span(&self) -> Span {
70		self.bang.to_span() + self.important.to_span()
71	}
72}
73
74impl SemanticEq for BangImportant {
75	fn semantic_eq(&self, _: &Self) -> bool {
76		// The presence of !important is semantic in of itself, so this is just always true
77		true
78	}
79}