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