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