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 #[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 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 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 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 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 Err(e @ (IntegerLeadingZeros | IntegerTooLarge)) => Err(self.dcx().err(e.to_string())),
118 Err(EmptyInteger) => Ok(LitKind::Err(ErrorGuaranteed::new_unchecked())),
120 Err(e @ ParseInteger(_)) => panic!("failed to parse integer literal {symbol:?}: {e}"),
122 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 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 Err(
137 e @ (EmptyRational | IntegerTooLarge | RationalTooLarge | ExponentTooLarge
138 | IntegerLeadingZeros),
139 ) => Err(self.dcx().err(e.to_string())),
140 Err(InvalidRational | EmptyExponent) => {
142 Ok(LitKind::Err(ErrorGuaranteed::new_unchecked()))
143 }
144 Err(e @ (ParseExponent(_) | ParseInteger(_) | ParseRational(_) | EmptyInteger)) => {
146 panic!("failed to parse rational literal {symbol:?}: {e}")
147 }
148 }
149 }
150
151 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 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 let (mut int, rat, exp) = match (s.find('.'), s.find(['e', 'E'])) {
260 (None, None) => (s, None, None),
262 (Some(dot), None) => {
264 let (int, rat) = split_at_exclusive(s, dot);
265 (int, Some(rat), None)
266 }
267 (None, Some(exp)) => {
269 let (int, exp) = split_at_exclusive(s, exp);
270 (int, None, Some(exp))
271 }
272 (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 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 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 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
362type Primitive = u128;
366
367const MAX_BITS: u32 = 4096;
369
370#[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
412fn fits_precision_base_10(mantissa: &BigUint, exp: u32) -> bool {
414 fits_precision_base_x(mantissa, std::f64::consts::LOG2_10, exp)
416}
417
418fn fits_precision_base_x(mantissa: &BigUint, log_2_of_base: f64, exp: u32) -> bool {
421 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 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 #[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_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("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("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}