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 AtKeyword {
101 value: Atom,
102 raw: Atom,
103 },
104 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 {
120 value: Atom,
121 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 WhiteSpace {
143 value: Atom,
144 },
145 CDO,
147 CDC,
149 Colon,
151 Semi,
153 Comma,
155 LBracket,
157 RBracket,
159 LParen,
161 RParen,
163 LBrace,
165 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 {}