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