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