swc_css_ast/
token.rs

1use std::hash::{Hash, Hasher};
2
3use is_macro::Is;
4#[cfg(feature = "serde-impl")]
5use serde::{Deserialize, Serialize};
6use swc_atoms::Atom;
7use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span};
8
9#[ast_node("PreservedToken")]
10#[derive(Eq, Hash, EqIgnoreSpan)]
11pub struct TokenAndSpan {
12    pub span: Span,
13    pub token: Token,
14}
15
16impl Take for TokenAndSpan {
17    fn dummy() -> Self {
18        Self {
19            span: Take::dummy(),
20            token: Take::dummy(),
21        }
22    }
23}
24
25#[derive(Debug, Clone, PartialEq, EqIgnoreSpan, Hash)]
26#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
27#[cfg_attr(
28    any(feature = "rkyv-impl"),
29    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
30)]
31#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
32#[cfg_attr(feature = "rkyv-impl", repr(C))]
33pub struct UrlKeyValue(pub Atom, pub Atom);
34
35#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Is, EqIgnoreSpan)]
36#[cfg_attr(
37    feature = "rkyv",
38    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
39)]
40#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))]
41#[cfg_attr(feature = "rkyv", repr(u32))]
42#[cfg_attr(
43    feature = "rkyv",
44    rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
45        __S::Error: rkyv::rancor::Source))
46)]
47#[cfg_attr(feature = "serde-impl", derive(Serialize, Deserialize))]
48pub enum NumberType {
49    #[cfg_attr(feature = "serde-impl", serde(rename = "integer"))]
50    Integer,
51    #[cfg_attr(feature = "serde-impl", serde(rename = "number"))]
52    Number,
53}
54
55#[derive(Debug, Clone, PartialEq, EqIgnoreSpan)]
56#[cfg_attr(
57    feature = "rkyv",
58    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
59)]
60#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))]
61#[cfg_attr(feature = "rkyv", repr(C))]
62#[cfg_attr(feature = "serde-impl", derive(Serialize, Deserialize))]
63pub struct DimensionToken {
64    pub value: f64,
65    pub raw_value: Atom,
66
67    pub unit: Atom,
68
69    #[cfg_attr(feature = "serde-impl", serde(rename = "type"))]
70    pub type_flag: NumberType,
71    pub raw_unit: Atom,
72}
73
74#[derive(Debug, Clone, PartialEq, EqIgnoreSpan)]
75#[cfg_attr(
76    feature = "rkyv",
77    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
78)]
79#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))]
80#[cfg_attr(feature = "rkyv", repr(u32))]
81#[cfg_attr(
82    feature = "rkyv",
83    rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
84        __S::Error: rkyv::rancor::Source))
85)]
86#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
87pub enum Token {
88    Ident {
89        value: Atom,
90        raw: Atom,
91    },
92    Function {
93        value: Atom,
94        raw: Atom,
95    },
96    /// `@`
97    AtKeyword {
98        value: Atom,
99        raw: Atom,
100    },
101    /// `#`
102    Hash {
103        is_id: bool,
104
105        value: Atom,
106        raw: Atom,
107    },
108    String {
109        value: Atom,
110        raw: Atom,
111    },
112    BadString {
113        raw: Atom,
114    },
115    /// `url(value)`
116    Url {
117        value: Atom,
118        /// Name and value
119        raw: Box<UrlKeyValue>,
120    },
121    BadUrl {
122        raw: Atom,
123    },
124    Delim {
125        value: char,
126    },
127    Number {
128        value: f64,
129        raw: Atom,
130        #[cfg_attr(feature = "serde-impl", serde(rename = "type"))]
131        type_flag: NumberType,
132    },
133    Percentage {
134        value: f64,
135        raw: Atom,
136    },
137    Dimension(Box<DimensionToken>),
138    /// One or more whitespace.
139    WhiteSpace {
140        value: Atom,
141    },
142    /// `<!--`
143    CDO,
144    /// `-->`
145    CDC,
146    /// `:``
147    Colon,
148    /// `;`
149    Semi,
150    /// `,`
151    Comma,
152    /// `[`
153    LBracket,
154    /// `]`
155    RBracket,
156    /// `(`
157    LParen,
158    /// `)`
159    RParen,
160    /// `{`
161    LBrace,
162    /// `}`
163    RBrace,
164}
165
166impl Take for Token {
167    fn dummy() -> Self {
168        Self::Semi
169    }
170}
171
172#[allow(clippy::derived_hash_with_manual_eq)]
173#[allow(clippy::transmute_float_to_int)]
174impl Hash for Token {
175    fn hash<H: Hasher>(&self, state: &mut H) {
176        fn integer_decode(val: f64) -> (u64, i16, i8) {
177            let bits: u64 = f64::to_bits(val);
178            let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
179            let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
180            let mantissa = if exponent == 0 {
181                (bits & 0xfffffffffffff) << 1
182            } else {
183                (bits & 0xfffffffffffff) | 0x10000000000000
184            };
185
186            exponent -= 1023 + 52;
187            (mantissa, exponent, sign)
188        }
189
190        match self {
191            Token::Ident { value, raw } => {
192                value.hash(state);
193                raw.hash(state);
194            }
195            Token::Function { value, raw } => {
196                value.hash(state);
197                raw.hash(state);
198            }
199            Token::AtKeyword { value, raw } => {
200                value.hash(state);
201                raw.hash(state);
202            }
203            Token::String { value, raw } => {
204                value.hash(state);
205                raw.hash(state);
206            }
207            Token::BadString { raw } => {
208                raw.hash(state);
209            }
210            Token::Hash { value, raw, is_id } => {
211                value.hash(state);
212                raw.hash(state);
213                is_id.hash(state);
214            }
215            Token::Url { value, raw } => {
216                value.hash(state);
217                raw.hash(state);
218            }
219            Token::BadUrl { raw, .. } => {
220                raw.hash(state);
221            }
222            Token::Delim { value } => {
223                value.hash(state);
224            }
225            Token::Number {
226                value,
227                raw,
228                type_flag,
229            } => {
230                integer_decode(*value).hash(state);
231                raw.hash(state);
232                type_flag.hash(state);
233            }
234            Token::Percentage { value, raw } => {
235                integer_decode(*value).hash(state);
236                raw.hash(state);
237            }
238            Token::Dimension(dimension) => {
239                integer_decode(dimension.value).hash(state);
240                dimension.unit.hash(state);
241                dimension.type_flag.hash(state);
242                dimension.raw_value.hash(state);
243                dimension.raw_unit.hash(state);
244            }
245            Token::WhiteSpace { value, .. } => {
246                value.hash(state);
247            }
248            Token::CDO
249            | Token::CDC
250            | Token::Colon
251            | Token::Semi
252            | Token::Comma
253            | Token::LBracket
254            | Token::RBracket
255            | Token::LParen
256            | Token::RParen
257            | Token::LBrace
258            | Token::RBrace => {}
259        }
260    }
261}
262
263impl Eq for Token {}