swc_css_ast/
token.rs

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