1use alloy_primitives::Address;
2use solar_interface::{Span, Symbol, diagnostics::ErrorGuaranteed, kw};
3use std::{fmt, sync::Arc};
4
5#[derive(Clone, Debug)]
13pub struct Lit {
14 pub span: Span,
16 pub symbol: Symbol,
22 pub kind: LitKind,
25}
26
27impl fmt::Display for Lit {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 let Self { ref kind, symbol, span: _ } = *self;
30 match kind {
31 LitKind::Str(StrKind::Str, ..) => write!(f, "\"{symbol}\""),
32 LitKind::Str(StrKind::Unicode, ..) => write!(f, "unicode\"{symbol}\""),
33 LitKind::Str(StrKind::Hex, ..) => write!(f, "hex\"{symbol}\""),
34 LitKind::Number(_)
35 | LitKind::Rational(_)
36 | LitKind::Err(_)
37 | LitKind::Address(_)
38 | LitKind::Bool(_) => write!(f, "{symbol}"),
39 }
40 }
41}
42
43impl Lit {
44 pub fn first_span(&self) -> Span {
46 if let LitKind::Str(kind, _, extra) = &self.kind
47 && !extra.is_empty()
48 {
49 let str_len = kind.prefix().len() + 1 + self.symbol.as_str().len() + 1;
50 return self.span.with_hi(self.span.lo() + str_len as u32);
51 }
52 self.span
53 }
54
55 pub fn literals(&self) -> impl Iterator<Item = (Span, Symbol)> + '_ {
57 let extra = if let LitKind::Str(_, _, extra) = &self.kind { extra.as_slice() } else { &[] };
58 std::iter::once((self.first_span(), self.symbol)).chain(extra.iter().copied())
59 }
60}
61
62#[derive(Clone)]
64pub enum LitKind {
65 Str(StrKind, Arc<[u8]>, Vec<(Span, Symbol)>),
83 Number(num_bigint::BigInt),
85 Rational(num_rational::BigRational),
90 Address(Address),
92 Bool(bool),
94 Err(ErrorGuaranteed),
96}
97
98impl fmt::Debug for LitKind {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 match self {
101 Self::Str(kind, value, extra) => {
102 write!(f, "{kind:?}(")?;
103 if let Ok(utf8) = std::str::from_utf8(value) {
104 write!(f, "{utf8:?}")?;
105 } else {
106 f.write_str(&alloy_primitives::hex::encode_prefixed(value))?;
107 }
108 if !extra.is_empty() {
109 write!(f, ", {extra:?}")?;
110 }
111 f.write_str(")")
112 }
113 Self::Number(value) => write!(f, "Number({value:?})"),
114 Self::Rational(value) => write!(f, "Rational({value:?})"),
115 Self::Address(value) => write!(f, "Address({value:?})"),
116 Self::Bool(value) => write!(f, "Bool({value:?})"),
117 Self::Err(_) => write!(f, "Err"),
118 }
119 }
120}
121
122impl LitKind {
123 pub fn description(&self) -> &'static str {
125 match self {
126 Self::Str(kind, ..) => kind.description(),
127 Self::Number(_) => "number",
128 Self::Rational(_) => "rational",
129 Self::Address(_) => "address",
130 Self::Bool(_) => "boolean",
131 Self::Err(_) => "<error>",
132 }
133 }
134}
135
136#[derive(Clone, Debug)]
138pub struct StrLit {
139 pub span: Span,
141 pub value: Symbol,
143}
144
145#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
147pub enum StrKind {
148 Str,
150 Unicode,
152 Hex,
154}
155
156impl StrKind {
157 pub fn description(self) -> &'static str {
159 match self {
160 Self::Str => "string",
161 Self::Unicode => "unicode string",
162 Self::Hex => "hex string",
163 }
164 }
165
166 #[doc(alias = "to_str")]
168 pub fn prefix(self) -> &'static str {
169 match self {
170 Self::Str => "",
171 Self::Unicode => "unicode",
172 Self::Hex => "hex",
173 }
174 }
175
176 #[doc(alias = "to_symbol")]
178 pub fn prefix_symbol(self) -> Symbol {
179 match self {
180 Self::Str => kw::Empty,
181 Self::Unicode => kw::Unicode,
182 Self::Hex => kw::Hex,
183 }
184 }
185}
186
187#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
189pub enum SubDenomination {
190 Ether(EtherSubDenomination),
192 Time(TimeSubDenomination),
194}
195
196impl fmt::Display for SubDenomination {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 match self {
199 Self::Ether(sub_denomination) => sub_denomination.fmt(f),
200 Self::Time(sub_denomination) => sub_denomination.fmt(f),
201 }
202 }
203}
204
205impl SubDenomination {
206 pub const fn to_str(self) -> &'static str {
208 match self {
209 Self::Ether(sub_denomination) => sub_denomination.to_str(),
210 Self::Time(sub_denomination) => sub_denomination.to_str(),
211 }
212 }
213
214 pub const fn to_symbol(self) -> Symbol {
216 match self {
217 Self::Ether(sub_denomination) => sub_denomination.to_symbol(),
218 Self::Time(sub_denomination) => sub_denomination.to_symbol(),
219 }
220 }
221
222 pub const fn value(self) -> u64 {
224 match self {
225 Self::Ether(sub_denomination) => sub_denomination.wei(),
226 Self::Time(sub_denomination) => sub_denomination.seconds(),
227 }
228 }
229}
230
231#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
233pub enum EtherSubDenomination {
234 Wei,
236 Gwei,
238 Ether,
240}
241
242impl fmt::Display for EtherSubDenomination {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 f.write_str(self.to_str())
245 }
246}
247
248impl EtherSubDenomination {
249 pub const fn to_str(self) -> &'static str {
251 match self {
252 Self::Wei => "wei",
253 Self::Gwei => "gwei",
254 Self::Ether => "ether",
255 }
256 }
257
258 pub const fn to_symbol(self) -> Symbol {
260 match self {
261 Self::Wei => kw::Wei,
262 Self::Gwei => kw::Gwei,
263 Self::Ether => kw::Ether,
264 }
265 }
266
267 pub const fn wei(self) -> u64 {
269 match self {
271 Self::Wei => 1,
272 Self::Gwei => 1_000_000_000,
273 Self::Ether => 1_000_000_000_000_000_000,
274 }
275 }
276}
277
278#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
280pub enum TimeSubDenomination {
281 Seconds,
283 Minutes,
285 Hours,
287 Days,
289 Weeks,
291 Years,
293}
294
295impl fmt::Display for TimeSubDenomination {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 f.write_str(self.to_str())
298 }
299}
300
301impl TimeSubDenomination {
302 pub const fn to_str(self) -> &'static str {
304 match self {
305 Self::Seconds => "seconds",
306 Self::Minutes => "minutes",
307 Self::Hours => "hours",
308 Self::Days => "days",
309 Self::Weeks => "weeks",
310 Self::Years => "years",
311 }
312 }
313
314 pub const fn to_symbol(self) -> Symbol {
316 match self {
317 Self::Seconds => kw::Seconds,
318 Self::Minutes => kw::Minutes,
319 Self::Hours => kw::Hours,
320 Self::Days => kw::Days,
321 Self::Weeks => kw::Weeks,
322 Self::Years => kw::Years,
323 }
324 }
325
326 pub const fn seconds(self) -> u64 {
328 match self {
330 Self::Seconds => 1,
331 Self::Minutes => 60,
332 Self::Hours => 3_600,
333 Self::Days => 86_400,
334 Self::Weeks => 604_800,
335 Self::Years => 31_536_000,
336 }
337 }
338}
339
340#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
342pub enum Base {
343 Binary = 2,
345 Octal = 8,
347 Decimal = 10,
349 Hexadecimal = 16,
351}
352
353impl fmt::Display for Base {
354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355 self.to_str().fmt(f)
356 }
357}
358
359impl Base {
360 pub fn to_str(self) -> &'static str {
362 match self {
363 Self::Binary => "binary",
364 Self::Octal => "octal",
365 Self::Decimal => "decimal",
366 Self::Hexadecimal => "hexadecimal",
367 }
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374 use solar_interface::{BytePos, enter};
375
376 #[test]
377 fn literal_fmt() {
378 enter(|| {
379 let lit = LitKind::Str(StrKind::Str, Arc::from(b"hello world" as &[u8]), vec![]);
380 assert_eq!(lit.description(), "string");
381 assert_eq!(format!("{lit:?}"), "Str(\"hello world\")");
382
383 let lit = LitKind::Str(StrKind::Str, Arc::from(b"hello\0world" as &[u8]), vec![]);
384 assert_eq!(lit.description(), "string");
385 assert_eq!(format!("{lit:?}"), "Str(\"hello\\0world\")");
386
387 let lit = LitKind::Str(StrKind::Str, Arc::from(&[255u8][..]), vec![]);
388 assert_eq!(lit.description(), "string");
389 assert_eq!(format!("{lit:?}"), "Str(0xff)");
390
391 let lit = LitKind::Str(
392 StrKind::Str,
393 Arc::from(b"hello world" as &[u8]),
394 vec![(Span::new(BytePos(69), BytePos(420)), Symbol::intern("world"))],
395 );
396 assert_eq!(lit.description(), "string");
397 assert_eq!(format!("{lit:?}"), "Str(\"hello world\", [(Span(69..420), \"world\")])");
398 })
399 }
400}