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 #[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 => 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 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 let (mut int, rat, exp) = match (s.find('.'), s.find(['e', 'E'])) {
257 (None, None) => (s, None, None),
259 (Some(dot), None) => {
261 let (int, rat) = split_at_exclusive(s, dot);
262 (int, Some(rat), None)
263 }
264 (None, Some(exp)) => {
266 let (int, exp) = split_at_exclusive(s, exp);
267 (int, None, Some(exp))
268 }
269 (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 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 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 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
359type Primitive = u128;
363
364const MAX_BITS: u32 = 4096;
366
367#[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
414fn fits_precision_base_10(mantissa: &BigUint, exp: u32) -> bool {
416 fits_precision_base_x(mantissa, std::f64::consts::LOG2_10, exp)
418}
419
420fn fits_precision_base_x(mantissa: &BigUint, log_2_of_base: f64, exp: u32) -> bool {
423 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 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 #[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_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("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("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}