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, 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(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(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    symbol: Symbol,
227    subdenomination: Option<SubDenomination>,
228) -> Result<LitKind<'ast>, LitError> {
229    let s = &strip_underscores(&symbol)[..];
230    let base = match s.as_bytes() {
231        [b'0', b'x', ..] => Base::Hexadecimal,
232        [b'0', b'o', ..] => Base::Octal,
233        [b'0', b'b', ..] => Base::Binary,
234        _ => Base::Decimal,
235    };
236
237    if base == Base::Decimal && s.starts_with('0') && s.len() > 1 {
238        return Err(LitError::IntegerLeadingZeros);
239    }
240
241    // Address literal.
242    if base == Base::Hexadecimal
243        && s.len() == 42
244        && let Ok(address) = s.parse()
245    {
246        return Ok(LitKind::Address(address));
247    }
248
249    let start = if base == Base::Decimal { 0 } else { 2 };
250    let s = &s[start..];
251    if s.is_empty() {
252        return Err(LitError::EmptyInteger);
253    }
254    let mut n = u256_from_str_radix(s, base)?;
255    if let Some(subdenomination) = subdenomination {
256        n = n.checked_mul(U256::from(subdenomination.value())).ok_or(LitError::IntegerTooLarge)?;
257    }
258    Ok(LitKind::Number(n))
259}
260
261fn parse_rational<'ast>(
262    symbol: Symbol,
263    subdenomination: Option<SubDenomination>,
264) -> Result<LitKind<'ast>, LitError> {
265    let s = &strip_underscores(&symbol)[..];
266    debug_assert!(!s.is_empty());
267
268    if matches!(s.get(..2), Some("0b" | "0o" | "0x")) {
269        return Err(LitError::InvalidRational);
270    }
271
272    // Split the string into integer, rational, and exponent parts.
273    let (mut int, rat, exp) = match (s.find('.'), s.find(['e', 'E'])) {
274        // X
275        (None, None) => (s, None, None),
276        // X.Y
277        (Some(dot), None) => {
278            let (int, rat) = split_at_exclusive(s, dot);
279            (int, Some(rat), None)
280        }
281        // XeZ
282        (None, Some(exp)) => {
283            let (int, exp) = split_at_exclusive(s, exp);
284            (int, None, Some(exp))
285        }
286        // X.YeZ
287        (Some(dot), Some(exp)) => {
288            if exp < dot {
289                return Err(LitError::InvalidRational);
290            }
291            let (int, rest) = split_at_exclusive(s, dot);
292            let (rat, exp) = split_at_exclusive(rest, exp - dot - 1);
293            (int, Some(rat), Some(exp))
294        }
295    };
296
297    if cfg!(debug_assertions) {
298        let mut reconstructed = String::from(int);
299        if let Some(rat) = rat {
300            reconstructed.push('.');
301            reconstructed.push_str(rat);
302        }
303        if let Some(exp) = exp {
304            let e = if s.contains('E') { 'E' } else { 'e' };
305            reconstructed.push(e);
306            reconstructed.push_str(exp);
307        }
308        assert_eq!(reconstructed, s, "{int:?} + {rat:?} + {exp:?}");
309    }
310
311    // `int` is allowed to be empty: `.1e1` is the same as `0.1e1`.
312    if int.is_empty() {
313        int = "0";
314    }
315    if rat.is_some_and(str::is_empty) {
316        return Err(LitError::EmptyRational);
317    }
318    if exp.is_some_and(str::is_empty) {
319        return Err(LitError::EmptyExponent);
320    }
321
322    if int.starts_with('0') && int.len() > 1 {
323        return Err(LitError::IntegerLeadingZeros);
324    }
325    // NOTE: leading zeros are allowed in the rational and exponent parts.
326
327    let rat = rat.map(|rat| rat.trim_end_matches('0'));
328    let (int_s, is_rat) = match rat {
329        Some(rat) => (&[int, rat].concat()[..], true),
330        None => (int, false),
331    };
332    let int = big_int_from_str_radix(int_s, Base::Decimal, is_rat)?;
333
334    let fract_len = rat.map_or(0, str::len);
335    let fract_len = u16::try_from(fract_len).map_err(|_| LitError::RationalTooLarge)?;
336    let denominator = pow10(fract_len as u32);
337    let mut number = Ratio::new(int, denominator);
338
339    // 0E... is always zero.
340    if number.is_zero() {
341        return Ok(LitKind::Number(U256::ZERO));
342    }
343
344    if let Some(exp) = exp {
345        let exp = exp.parse::<i32>().map_err(|e| match *e.kind() {
346            std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow => {
347                LitError::ExponentTooLarge
348            }
349            _ => LitError::ParseExponent(e),
350        })?;
351        let exp_abs = exp.unsigned_abs();
352        let power = || pow10(exp_abs);
353        if exp.is_negative() {
354            if !fits_precision_base_10(&number.denom().abs().into_parts().1, exp_abs) {
355                return Err(LitError::ExponentTooLarge);
356            }
357            number /= power();
358        } else if exp > 0 {
359            if !fits_precision_base_10(&number.numer().abs().into_parts().1, exp_abs) {
360                return Err(LitError::ExponentTooLarge);
361            }
362            number *= power();
363        }
364    }
365
366    if let Some(subdenomination) = subdenomination {
367        number *= BigInt::from(subdenomination.value());
368    }
369
370    if number.is_integer() {
371        big_to_u256(number.to_integer(), true).map(LitKind::Number)
372    } else {
373        let (numer, denom) = number.into_raw();
374        Ok(LitKind::Rational(Ratio::new(big_to_u256(numer, true)?, big_to_u256(denom, true)?)))
375    }
376}
377
378/// Primitive type to use for fast-path parsing.
379///
380/// If changed, update `max_digits` as well.
381type Primitive = u128;
382
383/// Maximum number of bits for a big number.
384const MAX_BITS: u32 = 4096;
385
386/// Returns the maximum number of digits in `base` radix that can be represented in `BITS` bits.
387///
388/// ```python
389/// import math
390/// def max_digits(bits, base):
391///     return math.floor(math.log(2**bits - 1, base)) + 1
392/// ```
393#[inline]
394const fn max_digits<const BITS: u32>(base: Base) -> usize {
395    if matches!(base, Base::Binary) {
396        return BITS as usize;
397    }
398    match BITS {
399        Primitive::BITS => match base {
400            Base::Binary => BITS as usize,
401            Base::Octal => 43,
402            Base::Decimal => 39,
403            Base::Hexadecimal => 33,
404        },
405        MAX_BITS => match base {
406            Base::Binary => BITS as usize,
407            Base::Octal => 1366,
408            Base::Decimal => 1234,
409            Base::Hexadecimal => 1025,
410        },
411        _ => panic!("unknown bits"),
412    }
413}
414
415fn u256_from_str_radix(s: &str, base: Base) -> Result<U256, LitError> {
416    if s.len() <= max_digits::<{ Primitive::BITS }>(base)
417        && let Ok(n) = Primitive::from_str_radix(s, base as u32)
418    {
419        return Ok(U256::from(n));
420    }
421    U256::from_str_radix(s, base as u64).map_err(|_| LitError::IntegerTooLarge)
422}
423
424fn big_int_from_str_radix(s: &str, base: Base, rat: bool) -> Result<BigInt, LitError> {
425    if s.len() > max_digits::<MAX_BITS>(base) {
426        return Err(if rat { LitError::RationalTooLarge } else { LitError::IntegerTooLarge });
427    }
428    if s.len() <= max_digits::<{ Primitive::BITS }>(base)
429        && let Ok(n) = Primitive::from_str_radix(s, base as u32)
430    {
431        return Ok(BigInt::from(n));
432    }
433    BigInt::from_str_radix(s, base as u32)
434        .map_err(|e| if rat { LitError::ParseRational(e) } else { LitError::ParseInteger(e) })
435}
436
437fn big_to_u256(big: BigInt, rat: bool) -> Result<U256, LitError> {
438    let (_, limbs) = big.to_u64_digits();
439    U256::checked_from_limbs_slice(&limbs).ok_or(if rat {
440        LitError::RationalTooLarge
441    } else {
442        LitError::IntegerTooLarge
443    })
444}
445
446fn pow10(exp: u32) -> BigInt {
447    if let Some(n) = 10usize.checked_pow(exp) {
448        BigInt::from(n)
449    } else {
450        BigInt::from(10u64).pow(exp)
451    }
452}
453
454/// Checks whether mantissa * (10 ** exp) fits into [`MAX_BITS`] bits.
455fn fits_precision_base_10(mantissa: &BigUint, exp: u32) -> bool {
456    // https://github.com/ethereum/solidity/blob/14232980e4b39dee72972f3e142db584f0848a16/libsolidity/ast/Types.cpp#L66
457    fits_precision_base_x(mantissa, std::f64::consts::LOG2_10, exp)
458}
459
460/// Checks whether `mantissa * (X ** exp)` fits into [`MAX_BITS`] bits,
461/// where `X` is given indirectly via `log_2_of_base = log2(X)`.
462fn fits_precision_base_x(mantissa: &BigUint, log_2_of_base: f64, exp: u32) -> bool {
463    // https://github.com/ethereum/solidity/blob/53c4facf4e01d603c21a8544fc3b016229628a16/libsolutil/Numeric.cpp#L25
464    if mantissa.is_zero() {
465        return true;
466    }
467
468    let max = MAX_BITS as u64;
469    let bits = mantissa.bits();
470    if bits > max {
471        return false;
472    }
473    let bits_needed = bits + f64::floor(log_2_of_base * exp as f64) as u64;
474    bits_needed <= max
475}
476
477#[track_caller]
478fn split_at_exclusive(s: &str, idx: usize) -> (&str, &str) {
479    (&s[..idx], &s[idx + 1..])
480}
481
482#[inline]
483fn strip_underscores(symbol: &Symbol) -> Cow<'_, str> {
484    // Do not allocate a new string unless necessary.
485    let s = symbol.as_str();
486    if s.contains('_') { Cow::Owned(strip_underscores_slow(s)) } else { Cow::Borrowed(s) }
487}
488
489#[inline(never)]
490#[cold]
491fn strip_underscores_slow(s: &str) -> String {
492    let mut s = s.to_string();
493    s.retain(|c| c != '_');
494    s
495}
496
497#[cfg(test)]
498mod tests {
499    use super::*;
500    use crate::Lexer;
501    use alloy_primitives::{Address, address};
502    use solar_interface::Session;
503
504    // String literal parsing is tested in ../lexer/mod.rs.
505
506    // Run through the lexer to get the same input that the parser gets.
507    #[track_caller]
508    fn lex_literal(src: &str, should_fail: bool) -> Symbol {
509        let sess = Session::builder().with_silent_emitter(None).build();
510        let tokens = Lexer::new(&sess, src).into_tokens();
511        assert_eq!(tokens.len(), 1, "expected exactly 1 token: {tokens:?}");
512        assert_eq!(sess.dcx.has_errors().is_err(), should_fail, "{src:?} -> {tokens:?}");
513        tokens[0].lit().expect("not a literal").symbol
514    }
515
516    #[test]
517    fn integer() {
518        use LitError::*;
519
520        #[track_caller]
521        fn check_int(src: &str, expected: Result<&str, LitError>) {
522            let symbol = lex_literal(src, false);
523            let res = match parse_integer(symbol, None) {
524                Ok(LitKind::Number(n)) => Ok(n),
525                Ok(x) => panic!("not a number: {x:?} ({src:?})"),
526                Err(e) => Err(e),
527            };
528            let expected = match expected {
529                Ok(s) => Ok(U256::from_str_radix(s, 10).unwrap()),
530                Err(e) => Err(e),
531            };
532            assert_eq!(res, expected, "{src:?}");
533        }
534
535        #[track_caller]
536        fn check_address(src: &str, expected: Result<Address, &str>) {
537            let symbol = lex_literal(src, false);
538            match expected {
539                Ok(address) => match parse_integer(symbol, None) {
540                    Ok(LitKind::Address(a)) => assert_eq!(a, address, "{src:?}"),
541                    e => panic!("not an address: {e:?} ({src:?})"),
542                },
543                Err(int) => match parse_integer(symbol, None) {
544                    Ok(LitKind::Number(n)) => {
545                        assert_eq!(n, U256::from_str_radix(int, 10).unwrap(), "{src:?}")
546                    }
547                    e => panic!("not an integer: {e:?} ({src:?})"),
548                },
549            }
550        }
551
552        solar_interface::enter(|| {
553            check_int("00", Err(IntegerLeadingZeros));
554            check_int("01", Err(IntegerLeadingZeros));
555            check_int("00", Err(IntegerLeadingZeros));
556            check_int("001", Err(IntegerLeadingZeros));
557            check_int("000", Err(IntegerLeadingZeros));
558            check_int("0001", Err(IntegerLeadingZeros));
559
560            check_int("0", Ok("0"));
561            check_int("1", Ok("1"));
562
563            // check("0b10", Ok("2"));
564            // check("0o10", Ok("8"));
565            check_int("10", Ok("10"));
566            check_int("0x10", Ok("16"));
567
568            check_address("0x00000000000000000000000000000000000000", Err("0"));
569            check_address("0x000000000000000000000000000000000000000", Err("0"));
570            check_address("0x0000000000000000000000000000000000000000", Ok(Address::ZERO));
571            check_address("0x00000000000000000000000000000000000000000", Err("0"));
572            check_address("0x000000000000000000000000000000000000000000", Err("0"));
573            check_address(
574                "0x0000000000000000000000000000000000000001",
575                Ok(Address::with_last_byte(1)),
576            );
577
578            check_address(
579                "0x52908400098527886E0F7030069857D2E4169EE7",
580                Ok(address!("0x52908400098527886E0F7030069857D2E4169EE7")),
581            );
582            check_address(
583                "0x52908400098527886E0F7030069857D2E4169Ee7",
584                Ok(address!("0x52908400098527886E0F7030069857D2E4169EE7")),
585            );
586
587            check_address(
588                "0x8617E340B3D01FA5F11F306F4090FD50E238070D",
589                Ok(address!("0x8617E340B3D01FA5F11F306F4090FD50E238070D")),
590            );
591            check_address(
592                "0xde709f2102306220921060314715629080e2fb77",
593                Ok(address!("0xde709f2102306220921060314715629080e2fb77")),
594            );
595            check_address(
596                "0x27b1fdb04752bbc536007a920d24acb045561c26",
597                Ok(address!("0x27b1fdb04752bbc536007a920d24acb045561c26")),
598            );
599            check_address(
600                "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
601                Ok(address!("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")),
602            );
603            check_address(
604                "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
605                Ok(address!("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359")),
606            );
607            check_address(
608                "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB",
609                Ok(address!("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB")),
610            );
611            check_address(
612                "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb",
613                Ok(address!("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")),
614            );
615        });
616    }
617
618    #[test]
619    fn rational() {
620        use LitError::*;
621
622        #[track_caller]
623        fn check_int_full(src: &str, should_fail_lexing: bool, expected: Result<&str, LitError>) {
624            let symbol = lex_literal(src, should_fail_lexing);
625            let res = match parse_rational(symbol, None) {
626                Ok(LitKind::Number(r)) => Ok(r),
627                Ok(x) => panic!("not a number: {x:?} ({src:?})"),
628                Err(e) => Err(e),
629            };
630            let expected = match expected {
631                Ok(s) => Ok(U256::from_str_radix(s, 10).unwrap()),
632                Err(e) => Err(e),
633            };
634            assert_eq!(res, expected, "{src:?}");
635        }
636
637        #[track_caller]
638        fn check_int(src: &str, expected: Result<&str, LitError>) {
639            check_int_full(src, false, expected);
640        }
641
642        #[track_caller]
643        fn check_rat(src: &str, expected: Result<&str, LitError>) {
644            let symbol = lex_literal(src, false);
645            let res = match parse_rational(symbol, None) {
646                Ok(LitKind::Rational(r)) => Ok(r),
647                Ok(x) => panic!("not a number: {x:?} ({src:?})"),
648                Err(e) => Err(e),
649            };
650            let expected = match expected {
651                Ok(s) => Ok(Ratio::from_str_radix(s, 10).unwrap()),
652                Err(e) => Err(e),
653            };
654            assert_eq!(res, expected, "{src:?}");
655        }
656
657        #[track_caller]
658        fn zeros(before: &str, zeros: usize) -> String {
659            before.to_string() + &"0".repeat(zeros)
660        }
661
662        solar_interface::enter(|| {
663            check_int("00", Err(IntegerLeadingZeros));
664            check_int("0_0", Err(IntegerLeadingZeros));
665            check_int("01", Err(IntegerLeadingZeros));
666            check_int("0_1", Err(IntegerLeadingZeros));
667            check_int("00", Err(IntegerLeadingZeros));
668            check_int("001", Err(IntegerLeadingZeros));
669            check_int("000", Err(IntegerLeadingZeros));
670            check_int("0001", Err(IntegerLeadingZeros));
671
672            check_int("0.", Err(EmptyRational));
673
674            check_int("0", Ok("0"));
675            check_int("0e0", Ok("0"));
676            check_int("0.0", Ok("0"));
677            check_int("0.00", Ok("0"));
678            check_int("0.0e0", Ok("0"));
679            check_int("0.00e0", Ok("0"));
680            check_int("0.0e00", Ok("0"));
681            check_int("0.00e00", Ok("0"));
682            check_int("0.0e-0", Ok("0"));
683            check_int("0.00e-0", Ok("0"));
684            check_int("0.0e-00", Ok("0"));
685            check_int("0.00e-00", Ok("0"));
686            check_int("0.0e1", Ok("0"));
687            check_int("0.00e1", Ok("0"));
688            check_int("0.00e01", Ok("0"));
689            check_int("0e999999", Ok("0"));
690            check_int("0E123456789", Ok("0"));
691
692            check_int(".0", Ok("0"));
693            check_int(".00", Ok("0"));
694            check_int(".0e0", Ok("0"));
695            check_int(".00e0", Ok("0"));
696            check_int(".0e00", Ok("0"));
697            check_int(".00e00", Ok("0"));
698            check_int(".0e-0", Ok("0"));
699            check_int(".00e-0", Ok("0"));
700            check_int(".0e-00", Ok("0"));
701            check_int(".00e-00", Ok("0"));
702            check_int(".0e1", Ok("0"));
703            check_int(".00e1", Ok("0"));
704            check_int(".00e01", Ok("0"));
705
706            check_int("1", Ok("1"));
707            check_int("1e0", Ok("1"));
708            check_int("1.0", Ok("1"));
709            check_int("1.00", Ok("1"));
710            check_int("1.0e0", Ok("1"));
711            check_int("1.00e0", Ok("1"));
712            check_int("1.0e00", Ok("1"));
713            check_int("1.00e00", Ok("1"));
714            check_int("1.0e-0", Ok("1"));
715            check_int("1.00e-0", Ok("1"));
716            check_int("1.0e-00", Ok("1"));
717            check_int("1.00e-00", Ok("1"));
718
719            check_int_full("0b", true, Err(InvalidRational));
720            check_int_full("0b0", true, Err(InvalidRational));
721            check_int_full("0b01", true, Err(InvalidRational));
722            check_int_full("0b01.0", true, Err(InvalidRational));
723            check_int_full("0b01.0e1", true, Err(InvalidRational));
724            check_int_full("0b0e", true, Err(InvalidRational));
725            // check_int_full("0b0e.0", true, Err(InvalidRational));
726            // check_int_full("0b0e.0e1", true, Err(InvalidRational));
727
728            check_int_full("0o", true, Err(InvalidRational));
729            check_int_full("0o0", true, Err(InvalidRational));
730            check_int_full("0o01", true, Err(InvalidRational));
731            check_int_full("0o01.0", true, Err(InvalidRational));
732            check_int_full("0o01.0e1", true, Err(InvalidRational));
733            check_int_full("0o0e", true, Err(InvalidRational));
734            // check_int_full("0o0e.0", true, Err(InvalidRational));
735            // check_int_full("0o0e.0e1", true, Err(InvalidRational));
736
737            check_int_full("0x", true, Err(InvalidRational));
738            check_int_full("0x0", false, Err(InvalidRational));
739            check_int_full("0x01", false, Err(InvalidRational));
740            check_int_full("0x01.0", true, Err(InvalidRational));
741            check_int_full("0x01.0e1", true, Err(InvalidRational));
742            check_int_full("0x0e", false, Err(InvalidRational));
743            check_int_full("0x0e.0", true, Err(InvalidRational));
744            check_int_full("0x0e.0e1", true, Err(InvalidRational));
745
746            check_int("1e1", Ok("10"));
747            check_int("1.0e1", Ok("10"));
748            check_int("1.00e1", Ok("10"));
749            check_int("1.00e01", Ok("10"));
750
751            check_int("1.1e1", Ok("11"));
752            check_int("1.10e1", Ok("11"));
753            check_int("1.100e1", Ok("11"));
754            check_int("1.2e1", Ok("12"));
755            check_int("1.200e1", Ok("12"));
756
757            check_int("1e10", Ok(&zeros("1", 10)));
758            check_int("1.0e10", Ok(&zeros("1", 10)));
759            check_int("1.1e10", Ok(&zeros("11", 9)));
760            check_int("10e-1", Ok("1"));
761            // check_int("1E1233", Ok(&zeros("1", 1233)));
762            // check_int("1E1234", Err(LitError::ExponentTooLarge));
763
764            check_rat("1e-1", Ok("1/10"));
765            check_rat("1e-2", Ok("1/100"));
766            check_rat("1e-3", Ok("1/1000"));
767            check_rat("1.0e-1", Ok("1/10"));
768            check_rat("1.0e-2", Ok("1/100"));
769            check_rat("1.0e-3", Ok("1/1000"));
770            check_rat("1.1e-1", Ok("11/100"));
771            check_rat("1.1e-2", Ok("11/1000"));
772            check_rat("1.1e-3", Ok("11/10000"));
773
774            check_rat("1.1", Ok("11/10"));
775            check_rat("1.10", Ok("11/10"));
776            check_rat("1.100", Ok("11/10"));
777            check_rat("1.2", Ok("12/10"));
778            check_rat("1.20", Ok("12/10"));
779        });
780    }
781}