solar_parse/parser/
lit.rs

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