solar_parse/parser/
lit.rs

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