Skip to main content

moxy_token/lit/
int.rs

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}