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