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 pub fn split(repr: &str) -> Result<(Self, &str), String> {
307 const PREFIXES: [&str; 6] = ["0b", "0B", "0o", "0O", "0x", "0X"];
308
309 for s in PREFIXES {
310 if let Some(body) = repr.strip_prefix(s) {
311 return Ok((s.parse()?, body));
312 }
313 }
314
315 Ok((Self::Decimal, repr))
316 }
317
318 #[inline]
319 pub const fn to_u8(self) -> u8 {
320 self as u8
321 }
322}
323
324impl From<Radix> for u8 {
325 fn from(value: Radix) -> Self {
326 value.to_u8()
327 }
328}
329
330impl From<Radix> for u32 {
331 fn from(value: Radix) -> Self {
332 value as u32
333 }
334}
335
336impl std::str::FromStr for Radix {
337 type Err = String;
338
339 fn from_str(s: &str) -> Result<Self, Self::Err> {
340 match s {
341 "0b" | "0B" => Ok(Self::Binary),
342 "0o" | "0O" => Ok(Self::Octal),
343 "0x" | "0X" => Ok(Self::Hex),
344 "" => Ok(Self::Decimal),
345 v => Err(format!("expected integer literal radix, received {v}")),
346 }
347 }
348}
349
350#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
352#[cfg_attr(feature = "serde", derive(serde::Serialize))]
353pub enum IntSuffix {
354 #[default]
355 None,
356 I8,
357 I16,
358 I32,
359 I64,
360 I128,
361 ISize,
362 U8,
363 U16,
364 U32,
365 U64,
366 U128,
367 USize,
368}
369
370impl IntSuffix {
371 pub fn split(repr: &str) -> Result<(&str, Self), String> {
372 const SUFFIXES: [&str; 12] = [
373 "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize",
374 ];
375
376 for s in SUFFIXES {
377 if let Some(body) = repr.strip_suffix(s) {
378 return Ok((body, s.parse()?));
379 }
380 }
381
382 Ok((repr, Self::None))
383 }
384
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}