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 AtKeyword {
98 value: Atom,
99 raw: Atom,
100 },
101 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 {
117 value: Atom,
118 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 WhiteSpace {
140 value: Atom,
141 },
142 CDO,
144 CDC,
146 Colon,
148 Semi,
150 Comma,
152 LBracket,
154 RBracket,
156 LParen,
158 RParen,
160 LBrace,
162 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 {}