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 #[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 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 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 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 Err(e @ (IntegerLeadingZeros | IntegerTooLarge)) => Err(self.dcx().err(e.to_string())),
117 Err(EmptyInteger) => Ok(LitKind::Err(ErrorGuaranteed::new_unchecked())),
119 Err(e @ ParseInteger(_)) => panic!("failed to parse integer literal {symbol:?}: {e}"),
121 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 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 Err(
140 e @ (EmptyRational | IntegerTooLarge | RationalTooLarge | ExponentTooLarge
141 | IntegerLeadingZeros),
142 ) => Err(self.dcx().err(e.to_string())),
143 Err(InvalidRational | EmptyExponent) => {
145 Ok(LitKind::Err(ErrorGuaranteed::new_unchecked()))
146 }
147 Err(e @ (ParseExponent(_) | ParseInteger(_) | ParseRational(_) | EmptyInteger)) => {
149 panic!("failed to parse rational literal {symbol:?}: {e}")
150 }
151 }
152 }
153
154 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 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 let (mut int, rat, exp) = match (s.find('.'), s.find(['e', 'E'])) {
274 (None, None) => (s, None, None),
276 (Some(dot), None) => {
278 let (int, rat) = split_at_exclusive(s, dot);
279 (int, Some(rat), None)
280 }
281 (None, Some(exp)) => {
283 let (int, exp) = split_at_exclusive(s, exp);
284 (int, None, Some(exp))
285 }
286 (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 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 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 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
378type Primitive = u128;
382
383const MAX_BITS: u32 = 4096;
385
386#[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
454fn fits_precision_base_10(mantissa: &BigUint, exp: u32) -> bool {
456 fits_precision_base_x(mantissa, std::f64::consts::LOG2_10, exp)
458}
459
460fn fits_precision_base_x(mantissa: &BigUint, log_2_of_base: f64, exp: u32) -> bool {
463 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 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 #[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_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("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("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_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}