1use crate::lex::Cursor;
2use crate::lit::Lit;
3use crate::{LexError, Scan, Span, Spanner, ToTokens, TokenStream, TokenTree};
4
5#[derive(Debug, Default, Clone)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "String"))]
8pub struct LitInt {
9 span: Span,
10 repr: Box<str>,
11 radix: Radix,
12 suffix: IntSuffix,
13 value: u128,
14}
15
16impl LitInt {
17 #[inline]
18 pub fn span(&self) -> Span {
19 self.span
20 }
21
22 #[inline]
23 pub fn repr(&self) -> &str {
24 &self.repr
25 }
26
27 #[inline]
28 pub fn radix(&self) -> Radix {
29 self.radix
30 }
31
32 #[inline]
33 pub fn suffix(&self) -> IntSuffix {
34 self.suffix
35 }
36
37 #[inline]
38 pub fn set_span(&mut self, span: Span) {
39 self.span = span;
40 }
41
42 #[inline]
43 pub fn value(&self) -> u128 {
44 self.value
45 }
46}
47
48impl PartialEq for LitInt {
49 fn eq(&self, other: &Self) -> bool {
50 self.value == other.value
51 }
52}
53
54impl Eq for LitInt {}
55
56impl std::hash::Hash for LitInt {
57 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
58 self.value.hash(state);
59 }
60}
61
62impl std::fmt::Display for LitInt {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(f, "{}", self.repr)
65 }
66}
67
68impl std::str::FromStr for LitInt {
69 type Err = LexError;
70
71 fn from_str(s: &str) -> Result<Self, Self::Err> {
72 let cursor = Cursor::new(s, 0);
73 let (_, value) = Self::scan(cursor)?;
74 Ok(value)
75 }
76}
77
78impl Spanner for LitInt {
79 fn span(&self) -> Span {
80 self.span
81 }
82}
83
84impl ToTokens for LitInt {
85 fn to_tokens(&self, tokens: &mut TokenStream) {
86 tokens.extend_one(TokenTree::Literal(self.clone().into()));
87 }
88}
89
90impl Scan for LitInt {
91 fn scan(cursor: Cursor<'_>) -> Result<(Cursor<'_>, Self), LexError> {
92 let end = scan(cursor)?;
93 let len = end.offset() as usize - cursor.offset() as usize;
94 let repr = &cursor.rest()[..len];
95 let span = cursor.span_to(&end);
96 let stripped_repr = repr.replace("_", "");
97 let (stripped_repr, suffix) = IntSuffix::split(&stripped_repr).map_err(|msg| cursor.error().message(msg))?;
98 let (radix, stripped_repr) = Radix::split(stripped_repr).map_err(|msg| cursor.error().message(msg))?;
99 let value = u128::from_str_radix(stripped_repr, radix.into()).map_err(|err| cursor.error().message(err))?;
100
101 Ok((
102 end,
103 Self {
104 span,
105 repr: repr.into(),
106 radix,
107 suffix,
108 value,
109 },
110 ))
111 }
112}
113
114impl From<LitInt> for Lit {
115 fn from(value: LitInt) -> Self {
116 Self::Int(value)
117 }
118}
119
120#[cfg(feature = "serde")]
121impl From<LitInt> for String {
122 fn from(value: LitInt) -> Self {
123 value.repr.into_string()
124 }
125}
126
127impl Lit {
128 pub fn u8_suffixed(value: u8) -> Self {
129 Self::Int(LitInt {
130 repr: value.to_string().into(),
131 suffix: IntSuffix::U8,
132 value: value as u128,
133 ..Default::default()
134 })
135 }
136
137 pub fn u8_unsuffixed(value: u8) -> Self {
138 Self::Int(LitInt {
139 repr: value.to_string().into(),
140 value: value as u128,
141 ..Default::default()
142 })
143 }
144
145 pub fn u16_suffixed(value: u16) -> Self {
146 Self::Int(LitInt {
147 repr: value.to_string().into(),
148 suffix: IntSuffix::U16,
149 value: value as u128,
150 ..Default::default()
151 })
152 }
153
154 pub fn u16_unsuffixed(value: u16) -> Self {
155 Self::Int(LitInt {
156 repr: value.to_string().into(),
157 value: value as u128,
158 ..Default::default()
159 })
160 }
161
162 pub fn u32_suffixed(value: u32) -> Self {
163 Self::Int(LitInt {
164 repr: value.to_string().into(),
165 suffix: IntSuffix::U32,
166 value: value as u128,
167 ..Default::default()
168 })
169 }
170
171 pub fn u32_unsuffixed(value: u32) -> Self {
172 Self::Int(LitInt {
173 repr: value.to_string().into(),
174 value: value as u128,
175 ..Default::default()
176 })
177 }
178
179 pub fn u64_suffixed(value: u64) -> Self {
180 Self::Int(LitInt {
181 repr: value.to_string().into(),
182 suffix: IntSuffix::U64,
183 value: value as u128,
184 ..Default::default()
185 })
186 }
187
188 pub fn u64_unsuffixed(value: u64) -> Self {
189 Self::Int(LitInt {
190 repr: value.to_string().into(),
191 value: value as u128,
192 ..Default::default()
193 })
194 }
195
196 pub fn usize_suffixed(value: usize) -> Self {
197 Self::Int(LitInt {
198 repr: value.to_string().into(),
199 suffix: IntSuffix::USize,
200 value: value as u128,
201 ..Default::default()
202 })
203 }
204
205 pub fn usize_unsuffixed(value: usize) -> Self {
206 Self::Int(LitInt {
207 repr: value.to_string().into(),
208 value: value as u128,
209 ..Default::default()
210 })
211 }
212
213 pub fn i8_suffixed(value: i8) -> Self {
214 Self::Int(LitInt {
215 repr: value.to_string().into(),
216 suffix: IntSuffix::I8,
217 value: value as u128,
218 ..Default::default()
219 })
220 }
221
222 pub fn i8_unsuffixed(value: i8) -> Self {
223 Self::Int(LitInt {
224 repr: value.to_string().into(),
225 value: value as u128,
226 ..Default::default()
227 })
228 }
229
230 pub fn i16_suffixed(value: i16) -> Self {
231 Self::Int(LitInt {
232 repr: value.to_string().into(),
233 suffix: IntSuffix::I16,
234 value: value as u128,
235 ..Default::default()
236 })
237 }
238
239 pub fn i16_unsuffixed(value: i16) -> Self {
240 Self::Int(LitInt {
241 repr: value.to_string().into(),
242 value: value as u128,
243 ..Default::default()
244 })
245 }
246
247 pub fn i32_suffixed(value: i32) -> Self {
248 Self::Int(LitInt {
249 repr: value.to_string().into(),
250 suffix: IntSuffix::I32,
251 value: value as u128,
252 ..Default::default()
253 })
254 }
255
256 pub fn i32_unsuffixed(value: i32) -> Self {
257 Self::Int(LitInt {
258 repr: value.to_string().into(),
259 value: value as u128,
260 ..Default::default()
261 })
262 }
263
264 pub fn i64_suffixed(value: i64) -> Self {
265 Self::Int(LitInt {
266 repr: value.to_string().into(),
267 suffix: IntSuffix::I64,
268 value: value as u128,
269 ..Default::default()
270 })
271 }
272
273 pub fn i64_unsuffixed(value: i64) -> Self {
274 Self::Int(LitInt {
275 repr: value.to_string().into(),
276 value: value as u128,
277 ..Default::default()
278 })
279 }
280
281 pub fn isize_suffixed(value: isize) -> Self {
282 Self::Int(LitInt {
283 repr: value.to_string().into(),
284 suffix: IntSuffix::ISize,
285 value: value as u128,
286 ..Default::default()
287 })
288 }
289
290 pub fn isize_unsuffixed(value: isize) -> Self {
291 Self::Int(LitInt {
292 repr: value.to_string().into(),
293 value: value as u128,
294 ..Default::default()
295 })
296 }
297}
298
299#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
301#[cfg_attr(feature = "serde", derive(serde::Serialize))]
302#[repr(u8)]
303pub enum Radix {
304 Binary = 2,
305 Octal = 8,
306 #[default]
307 Decimal = 10,
308 Hex = 16,
309}
310
311impl Radix {
312 pub fn split(repr: &str) -> Result<(Self, &str), String> {
313 const PREFIXES: [&str; 6] = ["0b", "0B", "0o", "0O", "0x", "0X"];
314
315 for s in PREFIXES {
316 if let Some(body) = repr.strip_prefix(s) {
317 return Ok((s.parse()?, body));
318 }
319 }
320
321 Ok((Self::Decimal, repr))
322 }
323
324 #[inline]
325 pub const fn to_u8(self) -> u8 {
326 self as u8
327 }
328}
329
330impl From<Radix> for u8 {
331 fn from(value: Radix) -> Self {
332 value.to_u8()
333 }
334}
335
336impl From<Radix> for u32 {
337 fn from(value: Radix) -> Self {
338 value as u32
339 }
340}
341
342impl std::str::FromStr for Radix {
343 type Err = String;
344
345 fn from_str(s: &str) -> Result<Self, Self::Err> {
346 match s {
347 "0b" | "0B" => Ok(Self::Binary),
348 "0o" | "0O" => Ok(Self::Octal),
349 "0x" | "0X" => Ok(Self::Hex),
350 "" => Ok(Self::Decimal),
351 v => Err(format!("expected integer literal radix, received {v}")),
352 }
353 }
354}
355
356#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
358#[cfg_attr(feature = "serde", derive(serde::Serialize))]
359pub enum IntSuffix {
360 #[default]
361 None,
362 I8,
363 I16,
364 I32,
365 I64,
366 I128,
367 ISize,
368 U8,
369 U16,
370 U32,
371 U64,
372 U128,
373 USize,
374}
375
376impl IntSuffix {
377 pub fn split(repr: &str) -> Result<(&str, Self), String> {
378 const SUFFIXES: [&str; 12] = [
379 "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize",
380 ];
381
382 for s in SUFFIXES {
383 if let Some(body) = repr.strip_suffix(s) {
384 return Ok((body, s.parse()?));
385 }
386 }
387
388 Ok((repr, Self::None))
389 }
390
391 pub fn as_str(self) -> &'static str {
392 match self {
393 Self::None => "",
394 Self::I8 => "i8",
395 Self::I16 => "i16",
396 Self::I32 => "i32",
397 Self::I64 => "i64",
398 Self::I128 => "i128",
399 Self::ISize => "isize",
400 Self::U8 => "u8",
401 Self::U16 => "u16",
402 Self::U32 => "u32",
403 Self::U64 => "u64",
404 Self::U128 => "u128",
405 Self::USize => "usize",
406 }
407 }
408}
409
410impl std::fmt::Display for IntSuffix {
411 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
412 write!(f, "{}", self.as_str())
413 }
414}
415
416impl std::str::FromStr for IntSuffix {
417 type Err = String;
418
419 fn from_str(s: &str) -> Result<Self, Self::Err> {
420 match s {
421 "" => Ok(Self::None),
422 "i8" => Ok(Self::I8),
423 "i16" => Ok(Self::I16),
424 "i32" => Ok(Self::I32),
425 "i64" => Ok(Self::I64),
426 "i128" => Ok(Self::I128),
427 "isize" => Ok(Self::ISize),
428 "u8" => Ok(Self::U8),
429 "u16" => Ok(Self::U16),
430 "u32" => Ok(Self::U32),
431 "u64" => Ok(Self::U64),
432 "u128" => Ok(Self::U128),
433 "usize" => Ok(Self::USize),
434 v => Err(format!("expected integer literal suffix, received {v}")),
435 }
436 }
437}
438
439fn scan(c: Cursor<'_>) -> Result<Cursor<'_>, LexError> {
440 let first = c.first().ok_or(c.error())?;
441
442 if !first.is_ascii_digit() {
443 return c.error().into();
444 }
445
446 let mut cur = c;
447
448 if first == '0' {
449 let next = cur.advance();
450
451 match next.first() {
452 Some('x' | 'X') => {
453 cur = digits(next.advance(), |ch| ch.is_ascii_hexdigit())?;
454 return Ok(suffix(cur));
455 }
456 Some('o' | 'O') => {
457 cur = digits(next.advance(), |ch| matches!(ch, '0'..='7'))?;
458 return Ok(suffix(cur));
459 }
460 Some('b' | 'B') => {
461 cur = digits(next.advance(), |ch| matches!(ch, '0' | '1'))?;
462 return Ok(suffix(cur));
463 }
464 _ => {}
465 }
466 }
467
468 cur = digits(cur, |ch| ch.is_ascii_digit())?;
469
470 if cur.starts_with(".") {
471 let after_dot = cur.advance();
472
473 if let Some(ch) = after_dot.first() {
474 if ch.is_ascii_digit() {
475 cur = digits_opt(after_dot, |ch| ch.is_ascii_digit());
476 }
477 }
478 }
479
480 if let Some('e' | 'E') = cur.first() {
481 cur = cur.advance();
482
483 if let Some('+' | '-') = cur.first() {
484 cur = cur.advance();
485 }
486
487 cur = digits(cur, |ch| ch.is_ascii_digit())?;
488 }
489
490 Ok(suffix(cur))
491}
492
493fn digits(c: Cursor<'_>, pred: fn(char) -> bool) -> Result<Cursor<'_>, LexError> {
494 let mut cur = c;
495 let mut found = false;
496
497 loop {
498 match cur.first() {
499 Some('_') => cur = cur.advance(),
500 Some(ch) if pred(ch) => {
501 found = true;
502 cur = cur.advance_by(ch.len_utf8());
503 }
504 _ => break,
505 }
506 }
507
508 if !found {
509 return c.error().into();
510 }
511
512 Ok(cur)
513}
514
515fn digits_opt(c: Cursor<'_>, pred: fn(char) -> bool) -> Cursor<'_> {
516 digits(c, pred).unwrap_or(c)
517}
518
519fn suffix(c: Cursor<'_>) -> Cursor<'_> {
520 match c.first() {
521 Some(ch) if ch == '_' || unicode_ident::is_xid_start(ch) => {
522 c.advance_by(ch.len_utf8()).skip_while(unicode_ident::is_xid_continue)
523 }
524 _ => c,
525 }
526}