solar_parse/parser/
lit.rs

1use crate::{PResult, Parser, unescape};
2use alloy_primitives::U256;
3use num_bigint::{BigInt, BigUint};
4use num_rational::Ratio;
5use num_traits::{Num, Signed, Zero};
6use solar_ast::{token::*, *};
7use solar_interface::{ByteSymbol, Session, Symbol, diagnostics::ErrorGuaranteed, kw};
8use std::{borrow::Cow, fmt};
9
10impl<'sess, 'ast> Parser<'sess, 'ast> {
11    /// Parses a literal with an optional subdenomination.
12    ///
13    /// Note that the subdenomination gets applied to the literal directly, and is returned just for
14    /// display reasons.
15    ///
16    /// Returns None if no subdenomination was parsed or if the literal is not a number or rational.
17    #[instrument(level = "trace", skip_all)]
18    pub fn parse_lit(
19        &mut self,
20        with_subdenomination: bool,
21    ) -> PResult<'sess, (Lit<'ast>, Option<SubDenomination>)> {
22        self.parse_spanned(|this| this.parse_lit_inner(with_subdenomination)).map(
23            |(span, (symbol, kind, subdenomination))| (Lit { span, symbol, kind }, subdenomination),
24        )
25    }
26
27    /// Parses a subdenomination.
28    pub fn parse_subdenomination(&mut self) -> Option<SubDenomination> {
29        let sub = self.subdenomination();
30        if sub.is_some() {
31            self.bump();
32        }
33        sub
34    }
35
36    fn subdenomination(&self) -> Option<SubDenomination> {
37        match self.token.ident()?.name {
38            kw::Wei => Some(SubDenomination::Ether(EtherSubDenomination::Wei)),
39            kw::Gwei => Some(SubDenomination::Ether(EtherSubDenomination::Gwei)),
40            kw::Ether => Some(SubDenomination::Ether(EtherSubDenomination::Ether)),
41
42            kw::Seconds => Some(SubDenomination::Time(TimeSubDenomination::Seconds)),
43            kw::Minutes => Some(SubDenomination::Time(TimeSubDenomination::Minutes)),
44            kw::Hours => Some(SubDenomination::Time(TimeSubDenomination::Hours)),
45            kw::Days => Some(SubDenomination::Time(TimeSubDenomination::Days)),
46            kw::Weeks => Some(SubDenomination::Time(TimeSubDenomination::Weeks)),
47            kw::Years => Some(SubDenomination::Time(TimeSubDenomination::Years)),
48
49            _ => None,
50        }
51    }
52
53    /// Emits an error if a subdenomination was parsed.
54    pub(super) fn expect_no_subdenomination(&mut self) {
55        if let Some(_sub) = self.parse_subdenomination() {
56            let span = self.prev_token.span;
57            self.dcx().err("subdenominations aren't allowed here").span(span).emit();
58        }
59    }
60
61    fn parse_lit_inner(
62        &mut self,
63        with_subdenomination: bool,
64    ) -> PResult<'sess, (Symbol, LitKind<'ast>, Option<SubDenomination>)> {
65        let lo = self.token.span;
66        if let TokenKind::Ident(symbol @ (kw::True | kw::False)) = self.token.kind {
67            self.bump();
68            let mut subdenomination =
69                if with_subdenomination { self.parse_subdenomination() } else { None };
70            self.subdenom_error(&mut subdenomination, lo.to(self.prev_token.span));
71            return Ok((symbol, LitKind::Bool(symbol != kw::False), subdenomination));
72        }
73
74        if !self.check_lit() {
75            return self.unexpected();
76        }
77
78        let Some(lit) = self.token.lit() else {
79            unreachable!("check_lit() returned true for non-literal token");
80        };
81        self.bump();
82        let mut subdenomination =
83            if with_subdenomination { self.parse_subdenomination() } else { None };
84        let result = match lit.kind {
85            TokenLitKind::Integer => self.parse_lit_int(lit.symbol, subdenomination),
86            TokenLitKind::Rational => self.parse_lit_rational(lit.symbol, subdenomination),
87            TokenLitKind::Str | TokenLitKind::UnicodeStr | TokenLitKind::HexStr => {
88                self.subdenom_error(&mut subdenomination, lo.to(self.prev_token.span));
89                self.parse_lit_str(lit)
90            }
91            TokenLitKind::Err(guar) => Ok(LitKind::Err(guar)),
92        };
93        let kind =
94            result.unwrap_or_else(|e| LitKind::Err(e.span(lo.to(self.prev_token.span)).emit()));
95        Ok((lit.symbol, kind, subdenomination))
96    }
97
98    fn subdenom_error(&mut self, slot: &mut Option<SubDenomination>, span: Span) {
99        if slot.is_some() {
100            *slot = None;
101            let msg = "sub-denominations are only allowed on number and rational literals";
102            self.dcx().err(msg).span(span).emit();
103        }
104    }
105
106    /// Parses an integer literal.
107    fn parse_lit_int(
108        &mut self,
109        symbol: Symbol,
110        subdenomination: Option<SubDenomination>,
111    ) -> PResult<'sess, LitKind<'ast>> {
112        use LitError::*;
113        match parse_integer(self.sess, symbol, subdenomination) {
114            Ok(l) => Ok(l),
115            // User error.
116            Err(e @ (IntegerLeadingZeros | IntegerTooLarge)) => Err(self.dcx().err(e.to_string())),
117            // User error, but already emitted.
118            Err(EmptyInteger) => Ok(LitKind::Err(ErrorGuaranteed::new_unchecked())),
119            // Lexer internal error.
120            Err(e @ ParseInteger(_)) => panic!("failed to parse integer literal {symbol:?}: {e}"),
121            // Should never happen.
122            Err(
123                e @ (InvalidRational | EmptyRational | EmptyExponent | ParseRational(_)
124                | ParseExponent(_) | RationalTooLarge | ExponentTooLarge),
125            ) => panic!("this error shouldn't happen for normal integer literals: {e}"),
126        }
127    }
128
129    /// Parses a rational literal.
130    fn parse_lit_rational(
131        &mut self,
132        symbol: Symbol,
133        subdenomination: Option<SubDenomination>,
134    ) -> PResult<'sess, LitKind<'ast>> {
135        use LitError::*;
136        match parse_rational(self.sess, symbol, subdenomination) {
137            Ok(l) => Ok(l),
138            // User error.
139            Err(
140                e @ (EmptyRational | IntegerTooLarge | RationalTooLarge | ExponentTooLarge
141                | IntegerLeadingZeros),
142            ) => Err(self.dcx().err(e.to_string())),
143            // User error, but already emitted.
144            Err(InvalidRational | EmptyExponent) => {
145                Ok(LitKind::Err(ErrorGuaranteed::new_unchecked()))
146            }
147            // Lexer internal error.
148            Err(e @ (ParseExponent(_) | ParseInteger(_) | ParseRational(_) | EmptyInteger)) => {
149                panic!("failed to parse rational literal {symbol:?}: {e}")
150            }
151        }
152    }
153
154    /// Parses a string literal.
155    fn parse_lit_str(&mut self, lit: TokenLit) -> PResult<'sess, LitKind<'ast>> {
156        let mode = match lit.kind {
157            TokenLitKind::Str => StrKind::Str,
158            TokenLitKind::UnicodeStr => StrKind::Unicode,
159            TokenLitKind::HexStr => StrKind::Hex,
160            _ => unreachable!(),
161        };
162
163        let span = self.prev_token.span;
164        let (mut value, _) =
165            unescape::parse_string_literal(lit.symbol.as_str(), mode, span, self.sess);
166        let mut extra = vec![];
167        while let Some(TokenLit { symbol, kind }) = self.token.lit() {
168            if kind != lit.kind {
169                break;
170            }
171            extra.push((self.token.span, symbol));
172            let (parsed, _) =
173                unescape::parse_string_literal(symbol.as_str(), mode, self.token.span, self.sess);
174            value.to_mut().extend_from_slice(&parsed);
175            self.bump();
176        }
177
178        let kind = match lit.kind {
179            TokenLitKind::Str => StrKind::Str,
180            TokenLitKind::UnicodeStr => StrKind::Unicode,
181            TokenLitKind::HexStr => StrKind::Hex,
182            _ => unreachable!(),
183        };
184        let extra = self.alloc_vec(extra);
185        Ok(LitKind::Str(kind, ByteSymbol::intern(&value), extra))
186    }
187}
188
189#[derive(Debug, PartialEq, Eq)]
190enum LitError {
191    InvalidRational,
192
193    EmptyInteger,
194    EmptyRational,
195    EmptyExponent,
196
197    ParseInteger(num_bigint::ParseBigIntError),
198    ParseRational(num_bigint::ParseBigIntError),
199    ParseExponent(std::num::ParseIntError),
200
201    IntegerTooLarge,
202    RationalTooLarge,
203    ExponentTooLarge,
204    IntegerLeadingZeros,
205}
206
207impl fmt::Display for LitError {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        match self {
210            Self::InvalidRational => write!(f, "invalid rational literal"),
211            Self::EmptyInteger => write!(f, "empty integer"),
212            Self::EmptyRational => write!(f, "empty rational"),
213            Self::EmptyExponent => write!(f, "empty exponent"),
214            Self::ParseInteger(e) => write!(f, "failed to parse integer: {e}"),
215            Self::ParseRational(e) => write!(f, "failed to parse rational: {e}"),
216            Self::ParseExponent(e) => write!(f, "failed to parse exponent: {e}"),
217            Self::IntegerTooLarge => write!(f, "integer part too large"),
218            Self::RationalTooLarge => write!(f, "rational part too large"),
219            Self::ExponentTooLarge => write!(f, "exponent too large"),
220            Self::IntegerLeadingZeros => write!(f, "leading zeros are not allowed in integers"),
221        }
222    }
223}
224
225fn parse_integer<'ast>(
226    sess: &Session,
227    symbol: Symbol,
228    subdenomination: Option<SubDenomination>,
229) -> Result<LitKind<'ast>, LitError> {
230    let s = &strip_underscores(symbol, sess)[..];
231    let base = match s.as_bytes() {
232        [b'0', b'x', ..] => Base::Hexadecimal,
233        [b'0', b'o', ..] => Base::Octal,
234        [b'0', b'b', ..] => Base::Binary,
235        _ => Base::Decimal,
236    };
237
238    if base == Base::Decimal && s.starts_with('0') && s.len() > 1 {
239        return Err(LitError::IntegerLeadingZeros);
240    }
241
242    // Address literal.
243    if base == Base::Hexadecimal
244        && s.len() == 42
245        && let Ok(address) = s.parse()
246    {
247        return Ok(LitKind::Address(address));
248    }
249
250    let start = if base == Base::Decimal { 0 } else { 2 };
251    let s = &s[start..];
252    if s.is_empty() {
253        return Err(LitError::EmptyInteger);
254    }
255    let mut n = u256_from_str_radix(s, base)?;
256    if let Some(subdenomination) = subdenomination {
257        n = n.checked_mul(U256::from(subdenomination.value())).ok_or(LitError::IntegerTooLarge)?;
258    }
259    Ok(LitKind::Number(n))
260}
261
262fn parse_rational<'ast>(
263    sess: &Session,
264    symbol: Symbol,
265    subdenomination: Option<SubDenomination>,
266) -> Result<LitKind<'ast>, LitError> {
267    let s = &strip_underscores(symbol, sess)[..];
268    debug_assert!(!s.is_empty());
269
270    if matches!(s.get(..2), Some("0b" | "0o" | "0x")) {
271        return Err(LitError::InvalidRational);
272    }
273
274    // Split the string into integer, rational, and exponent parts.
275    let (mut int, rat, exp) = match (s.find('.'), s.find(['e', 'E'])) {
276        // X
277        (None, None) => (s, None, None),
278        // X.Y
279        (Some(dot), None) => {
280            let (int, rat) = split_at_exclusive(s, dot);
281            (int, Some(rat), None)
282        }
283        // XeZ
284        (None, Some(exp)) => {
285            let (int, exp) = split_at_exclusive(s, exp);
286            (int, None, Some(exp))
287        }
288        // X.YeZ
289        (Some(dot), Some(exp)) => {
290            if exp < dot {
291                return Err(LitError::InvalidRational);
292            }
293            let (int, rest) = split_at_exclusive(s, dot);
294            let (rat, exp) = split_at_exclusive(rest, exp - dot - 1);
295            (int, Some(rat), Some(exp))
296        }
297    };
298
299    if cfg!(debug_assertions) {
300        let mut reconstructed = String::from(int);
301        if let Some(rat) = rat {
302            reconstructed.push('.');
303            reconstructed.push_str(rat);
304        }
305        if let Some(exp) = exp {
306            let e = if s.contains('E') { 'E' } else { 'e' };
307            reconstructed.push(e);
308            reconstructed.push_str(exp);
309        }
310        assert_eq!(reconstructed, s, "{int:?} + {rat:?} + {exp:?}");
311    }
312
313    // `int` is allowed to be empty: `.1e1` is the same as `0.1e1`.
314    if int.is_empty() {
315        int = "0";
316    }
317    if rat.is_some_and(str::is_empty) {
318        return Err(LitError::EmptyRational);
319    }
320    if exp.is_some_and(str::is_empty) {
321        return Err(LitError::EmptyExponent);
322    }
323
324    if int.starts_with('0') && int.len() > 1 {
325        return Err(LitError::IntegerLeadingZeros);
326    }
327    // NOTE: leading zeros are allowed in the rational and exponent parts.
328
329    let rat = rat.map(|rat| rat.trim_end_matches('0'));
330    let (int_s, is_rat) = match rat {
331        Some(rat) => (&[int, rat].concat()[..], true),
332        None => (int, false),
333    };
334    let int = big_int_from_str_radix(int_s, Base::Decimal, is_rat)?;
335
336    let fract_len = rat.map_or(0, str::len);
337    let fract_len = u16::try_from(fract_len).map_err(|_| LitError::RationalTooLarge)?;
338    let denominator = pow10(fract_len as u32);
339    let mut number = Ratio::new(int, denominator);
340
341    // 0E... is always zero.
342    if number.is_zero() {
343        return Ok(LitKind::Number(U256::ZERO));
344    }
345
346    if let Some(exp) = exp {
347        let exp = exp.parse::<i32>().map_err(|e| match *e.kind() {
348            std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow => {
349                LitError::ExponentTooLarge
350            }
351            _ => LitError::ParseExponent(e),
352        })?;
353        let exp_abs = exp.unsigned_abs();
354        let power = || pow10(exp_abs);
355        if exp.is_negative() {
356            if !fits_precision_base_10(&number.denom().abs().into_parts().1, exp_abs) {
357                return Err(LitError::ExponentTooLarge);
358            }
359            number /= power();
360        } else if exp > 0 {
361            if !fits_precision_base_10(&number.numer().abs().into_parts().1, exp_abs) {
362                return Err(LitError::ExponentTooLarge);
363            }
364            number *= power();
365        }
366    }
367
368    if let Some(subdenomination) = subdenomination {
369        number *= BigInt::from(subdenomination.value());
370    }
371
372    if number.is_integer() {
373        big_to_u256(number.to_integer(), true).map(LitKind::Number)
374    } else {
375        let (numer, denom) = number.into_raw();
376        Ok(LitKind::Rational(Ratio::new(big_to_u256(numer, true)?, big_to_u256(denom, true)?)))
377    }
378}
379
380/// Primitive type to use for fast-path parsing.
381///
382/// If changed, update `max_digits` as well.
383type Primitive = u128;
384
385/// Maximum number of bits for a big number.
386const MAX_BITS: u32 = 4096;
387
388/// Returns the maximum number of digits in `base` radix that can be represented in `BITS` bits.
389///
390/// ```python
391/// import math
392/// def max_digits(bits, base):
393///     return math.floor(math.log(2**bits - 1, base)) + 1
394/// ```
395#[inline]
396const fn max_digits<const BITS: u32>(base: Base) -> usize {
397    if matches!(base, Base::Binary) {
398        return BITS as usize;
399    }
400    match BITS {
401        Primitive::BITS => match base {
402            Base::Binary => BITS as usize,
403            Base::Octal => 43,
404            Base::Decimal => 39,
405            Base::Hexadecimal => 33,
406        },
407        MAX_BITS => match base {
408            Base::Binary => BITS as usize,
409            Base::Octal => 1366,
410            Base::Decimal => 1234,
411            Base::Hexadecimal => 1025,
412        },
413        _ => panic!("unknown bits"),
414    }
415}
416
417fn u256_from_str_radix(s: &str, base: Base) -> Result<U256, LitError> {
418    if s.len() <= max_digits::<{ Primitive::BITS }>(base)
419        && let Ok(n) = Primitive::from_str_radix(s, base as u32)
420    {
421        return Ok(U256::from(n));
422    }
423    U256::from_str_radix(s, base as u64).map_err(|_| LitError::IntegerTooLarge)
424}
425
426fn big_int_from_str_radix(s: &str, base: Base, rat: bool) -> Result<BigInt, LitError> {
427    if s.len() > max_digits::<MAX_BITS>(base) {
428        return Err(if rat { LitError::RationalTooLarge } else { LitError::IntegerTooLarge });
429    }
430    if s.len() <= max_digits::<{ Primitive::BITS }>(base)
431        && let Ok(n) = Primitive::from_str_radix(s, base as u32)
432    {
433        return Ok(BigInt::from(n));
434    }
435    BigInt::from_str_radix(s, base as u32)
436        .map_err(|e| if rat { LitError::ParseRational(e) } else { LitError::ParseInteger(e) })
437}
438
439fn big_to_u256(big: BigInt, rat: bool) -> Result<U256, LitError> {
440    let (_, limbs) = big.to_u64_digits();
441    U256::checked_from_limbs_slice(&limbs).ok_or(if rat {
442        LitError::RationalTooLarge
443    } else {
444        LitError::IntegerTooLarge
445    })
446}
447
448fn pow10(exp: u32) -> BigInt {
449    if let Some(n) = 10usize.checked_pow(exp) {
450        BigInt::from(n)
451    } else {
452        BigInt::from(10u64).pow(exp)
453    }
454}
455
456/// Checks whether mantissa * (10 ** exp) fits into [`MAX_BITS`] bits.
457fn fits_precision_base_10(mantissa: &BigUint, exp: u32) -> bool {
458    // https://github.com/argotorg/solidity/blob/14232980e4b39dee72972f3e142db584f0848a16/libsolidity/ast/Types.cpp#L66
459    fits_precision_base_x(mantissa, std::f64::consts::LOG2_10, exp)
460}
461
462/// Checks whether `mantissa * (X ** exp)` fits into [`MAX_BITS`] bits,
463/// where `X` is given indirectly via `log_2_of_base = log2(X)`.
464fn fits_precision_base_x(mantissa: &BigUint, log_2_of_base: f64, exp: u32) -> bool {
465    // https://github.com/argotorg/solidity/blob/53c4facf4e01d603c21a8544fc3b016229628a16/libsolutil/Numeric.cpp#L25
466    if mantissa.is_zero() {
467        return true;
468    }
469
470    let max = MAX_BITS as u64;
471    let bits = mantissa.bits();
472    if bits > max {
473        return false;
474    }
475    let bits_needed = bits + f64::floor(log_2_of_base * exp as f64) as u64;
476    bits_needed <= max
477}
478
479#[track_caller]
480fn split_at_exclusive(s: &str, idx: usize) -> (&str, &str) {
481    (&s[..idx], &s[idx + 1..])
482}
483
484#[inline]
485fn strip_underscores(symbol: Symbol, sess: &Session) -> Cow<'_, str> {
486    // Do not allocate a new string unless necessary.
487    let s = symbol.as_str_in(sess);
488    if s.contains('_') { Cow::Owned(strip_underscores_slow(s)) } else { Cow::Borrowed(s) }
489}
490
491#[inline(never)]
492#[cold]
493fn strip_underscores_slow(s: &str) -> String {
494    let mut s = s.to_string();
495    s.retain(|c| c != '_');
496    s
497}
498
499#[cfg(test)]
500mod tests {
501    use super::*;
502    use crate::Lexer;
503    use alloy_primitives::{Address, address};
504    use solar_interface::Session;
505
506    // String literal parsing is tested in ../lexer/mod.rs.
507
508    // Run through the lexer to get the same input that the parser gets.
509    #[track_caller]
510    fn lex_literal(src: &str, should_fail: bool, f: impl FnOnce(&Session, Symbol)) {
511        let sess =
512            Session::builder().with_buffer_emitter(Default::default()).single_threaded().build();
513        sess.enter_sequential(|| {
514            let file = sess.source_map().new_source_file("test".to_string(), src).unwrap();
515            let tokens = Lexer::from_source_file(&sess, &file).into_tokens();
516            let diags = sess.dcx.emitted_diagnostics().unwrap();
517            assert_eq!(tokens.len(), 1, "expected exactly 1 token: {tokens:?}\n{diags}");
518            assert_eq!(
519                sess.dcx.has_errors().is_err(),
520                should_fail,
521                "{src:?} -> {tokens:?};\n{diags}",
522            );
523            f(&sess, tokens[0].lit().expect("not a literal").symbol)
524        });
525    }
526
527    #[test]
528    fn integer() {
529        use LitError::*;
530
531        #[track_caller]
532        fn check_int(src: &str, expected: Result<&str, LitError>) {
533            lex_literal(src, false, |sess, symbol| {
534                let res = match parse_integer(sess, symbol, None) {
535                    Ok(LitKind::Number(n)) => Ok(n),
536                    Ok(x) => panic!("not a number: {x:?} ({src:?})"),
537                    Err(e) => Err(e),
538                };
539                let expected = match expected {
540                    Ok(s) => Ok(U256::from_str_radix(s, 10).unwrap()),
541                    Err(e) => Err(e),
542                };
543                assert_eq!(res, expected, "{src:?}");
544            });
545        }
546
547        #[track_caller]
548        fn check_address(src: &str, expected: Result<Address, &str>) {
549            lex_literal(src, false, |sess, symbol| match expected {
550                Ok(address) => match parse_integer(sess, symbol, None) {
551                    Ok(LitKind::Address(a)) => assert_eq!(a, address, "{src:?}"),
552                    e => panic!("not an address: {e:?} ({src:?})"),
553                },
554                Err(int) => match parse_integer(sess, symbol, None) {
555                    Ok(LitKind::Number(n)) => {
556                        assert_eq!(n, U256::from_str_radix(int, 10).unwrap(), "{src:?}")
557                    }
558                    e => panic!("not an integer: {e:?} ({src:?})"),
559                },
560            });
561        }
562
563        check_int("00", Err(IntegerLeadingZeros));
564        check_int("01", Err(IntegerLeadingZeros));
565        check_int("00", Err(IntegerLeadingZeros));
566        check_int("001", Err(IntegerLeadingZeros));
567        check_int("000", Err(IntegerLeadingZeros));
568        check_int("0001", Err(IntegerLeadingZeros));
569
570        check_int("0", Ok("0"));
571        check_int("1", Ok("1"));
572
573        // check("0b10", Ok("2"));
574        // check("0o10", Ok("8"));
575        check_int("10", Ok("10"));
576        check_int("0x10", Ok("16"));
577
578        check_address("0x00000000000000000000000000000000000000", Err("0"));
579        check_address("0x000000000000000000000000000000000000000", Err("0"));
580        check_address("0x0000000000000000000000000000000000000000", Ok(Address::ZERO));
581        check_address("0x00000000000000000000000000000000000000000", Err("0"));
582        check_address("0x000000000000000000000000000000000000000000", Err("0"));
583        check_address("0x0000000000000000000000000000000000000001", Ok(Address::with_last_byte(1)));
584
585        check_address(
586            "0x52908400098527886E0F7030069857D2E4169EE7",
587            Ok(address!("0x52908400098527886E0F7030069857D2E4169EE7")),
588        );
589        check_address(
590            "0x52908400098527886E0F7030069857D2E4169Ee7",
591            Ok(address!("0x52908400098527886E0F7030069857D2E4169EE7")),
592        );
593
594        check_address(
595            "0x8617E340B3D01FA5F11F306F4090FD50E238070D",
596            Ok(address!("0x8617E340B3D01FA5F11F306F4090FD50E238070D")),
597        );
598        check_address(
599            "0xde709f2102306220921060314715629080e2fb77",
600            Ok(address!("0xde709f2102306220921060314715629080e2fb77")),
601        );
602        check_address(
603            "0x27b1fdb04752bbc536007a920d24acb045561c26",
604            Ok(address!("0x27b1fdb04752bbc536007a920d24acb045561c26")),
605        );
606        check_address(
607            "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
608            Ok(address!("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")),
609        );
610        check_address(
611            "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
612            Ok(address!("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359")),
613        );
614        check_address(
615            "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB",
616            Ok(address!("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB")),
617        );
618        check_address(
619            "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb",
620            Ok(address!("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")),
621        );
622    }
623
624    #[test]
625    fn rational() {
626        use LitError::*;
627
628        #[track_caller]
629        fn check_int_full(src: &str, should_fail_lexing: bool, expected: Result<&str, LitError>) {
630            lex_literal(src, should_fail_lexing, |sess, symbol| {
631                let res = match parse_rational(sess, symbol, None) {
632                    Ok(LitKind::Number(r)) => Ok(r),
633                    Ok(x) => panic!("not a number: {x:?} ({src:?})"),
634                    Err(e) => Err(e),
635                };
636                let expected = match expected {
637                    Ok(s) => Ok(U256::from_str_radix(s, 10).unwrap()),
638                    Err(e) => Err(e),
639                };
640                assert_eq!(res, expected, "{src:?}");
641            });
642        }
643
644        #[track_caller]
645        fn check_int(src: &str, expected: Result<&str, LitError>) {
646            check_int_full(src, false, expected);
647        }
648
649        #[track_caller]
650        fn check_rat(src: &str, expected: Result<&str, LitError>) {
651            lex_literal(src, false, |sess, symbol| {
652                let res = match parse_rational(sess, symbol, None) {
653                    Ok(LitKind::Rational(r)) => Ok(r),
654                    Ok(x) => panic!("not a number: {x:?} ({src:?})"),
655                    Err(e) => Err(e),
656                };
657                let expected = match expected {
658                    Ok(s) => Ok(Ratio::from_str_radix(s, 10).unwrap()),
659                    Err(e) => Err(e),
660                };
661                assert_eq!(res, expected, "{src:?}");
662            });
663        }
664
665        #[track_caller]
666        fn zeros(before: &str, zeros: usize) -> String {
667            before.to_string() + &"0".repeat(zeros)
668        }
669
670        check_int("00", Err(IntegerLeadingZeros));
671        check_int("0_0", Err(IntegerLeadingZeros));
672        check_int("01", Err(IntegerLeadingZeros));
673        check_int("0_1", Err(IntegerLeadingZeros));
674        check_int("00", Err(IntegerLeadingZeros));
675        check_int("001", Err(IntegerLeadingZeros));
676        check_int("000", Err(IntegerLeadingZeros));
677        check_int("0001", Err(IntegerLeadingZeros));
678
679        check_int("0.", Err(EmptyRational));
680
681        check_int("0", Ok("0"));
682        check_int("0e0", Ok("0"));
683        check_int("0.0", Ok("0"));
684        check_int("0.00", Ok("0"));
685        check_int("0.0e0", Ok("0"));
686        check_int("0.00e0", Ok("0"));
687        check_int("0.0e00", Ok("0"));
688        check_int("0.00e00", Ok("0"));
689        check_int("0.0e-0", Ok("0"));
690        check_int("0.00e-0", Ok("0"));
691        check_int("0.0e-00", Ok("0"));
692        check_int("0.00e-00", Ok("0"));
693        check_int("0.0e1", Ok("0"));
694        check_int("0.00e1", Ok("0"));
695        check_int("0.00e01", Ok("0"));
696        check_int("0e999999", Ok("0"));
697        check_int("0E123456789", Ok("0"));
698
699        check_int(".0", Ok("0"));
700        check_int(".00", Ok("0"));
701        check_int(".0e0", Ok("0"));
702        check_int(".00e0", Ok("0"));
703        check_int(".0e00", Ok("0"));
704        check_int(".00e00", Ok("0"));
705        check_int(".0e-0", Ok("0"));
706        check_int(".00e-0", Ok("0"));
707        check_int(".0e-00", Ok("0"));
708        check_int(".00e-00", Ok("0"));
709        check_int(".0e1", Ok("0"));
710        check_int(".00e1", Ok("0"));
711        check_int(".00e01", Ok("0"));
712
713        check_int("1", Ok("1"));
714        check_int("1e0", Ok("1"));
715        check_int("1.0", Ok("1"));
716        check_int("1.00", Ok("1"));
717        check_int("1.0e0", Ok("1"));
718        check_int("1.00e0", Ok("1"));
719        check_int("1.0e00", Ok("1"));
720        check_int("1.00e00", Ok("1"));
721        check_int("1.0e-0", Ok("1"));
722        check_int("1.00e-0", Ok("1"));
723        check_int("1.0e-00", Ok("1"));
724        check_int("1.00e-00", Ok("1"));
725
726        check_int_full("0b", true, Err(InvalidRational));
727        check_int_full("0b0", true, Err(InvalidRational));
728        check_int_full("0b01", true, Err(InvalidRational));
729        check_int_full("0b01.0", true, Err(InvalidRational));
730        check_int_full("0b01.0e1", true, Err(InvalidRational));
731        check_int_full("0b0e", true, Err(InvalidRational));
732        // check_int_full("0b0e.0", true, Err(InvalidRational));
733        // check_int_full("0b0e.0e1", true, Err(InvalidRational));
734
735        check_int_full("0o", true, Err(InvalidRational));
736        check_int_full("0o0", true, Err(InvalidRational));
737        check_int_full("0o01", true, Err(InvalidRational));
738        check_int_full("0o01.0", true, Err(InvalidRational));
739        check_int_full("0o01.0e1", true, Err(InvalidRational));
740        check_int_full("0o0e", true, Err(InvalidRational));
741        // check_int_full("0o0e.0", true, Err(InvalidRational));
742        // check_int_full("0o0e.0e1", true, Err(InvalidRational));
743
744        check_int_full("0x", true, Err(InvalidRational));
745        check_int_full("0x0", false, Err(InvalidRational));
746        check_int_full("0x01", false, Err(InvalidRational));
747        check_int_full("0x01.0", true, Err(InvalidRational));
748        check_int_full("0x01.0e1", true, Err(InvalidRational));
749        check_int_full("0x0e", false, Err(InvalidRational));
750        check_int_full("0x0e.0", true, Err(InvalidRational));
751        check_int_full("0x0e.0e1", true, Err(InvalidRational));
752
753        check_int("1e1", Ok("10"));
754        check_int("1.0e1", Ok("10"));
755        check_int("1.00e1", Ok("10"));
756        check_int("1.00e01", Ok("10"));
757
758        check_int("1.1e1", Ok("11"));
759        check_int("1.10e1", Ok("11"));
760        check_int("1.100e1", Ok("11"));
761        check_int("1.2e1", Ok("12"));
762        check_int("1.200e1", Ok("12"));
763
764        check_int("1e10", Ok(&zeros("1", 10)));
765        check_int("1.0e10", Ok(&zeros("1", 10)));
766        check_int("1.1e10", Ok(&zeros("11", 9)));
767        check_int("10e-1", Ok("1"));
768        // check_int("1E1233", Ok(&zeros("1", 1233)));
769        // check_int("1E1234", Err(LitError::ExponentTooLarge));
770
771        check_rat("1e-1", Ok("1/10"));
772        check_rat("1e-2", Ok("1/100"));
773        check_rat("1e-3", Ok("1/1000"));
774        check_rat("1.0e-1", Ok("1/10"));
775        check_rat("1.0e-2", Ok("1/100"));
776        check_rat("1.0e-3", Ok("1/1000"));
777        check_rat("1.1e-1", Ok("11/100"));
778        check_rat("1.1e-2", Ok("11/1000"));
779        check_rat("1.1e-3", Ok("11/10000"));
780
781        check_rat("1.1", Ok("11/10"));
782        check_rat("1.10", Ok("11/10"));
783        check_rat("1.100", Ok("11/10"));
784        check_rat("1.2", Ok("12/10"));
785        check_rat("1.20", Ok("12/10"));
786    }
787}