Browse Source

uint[1.111111E1111111111111] causes compiler to go into infinite loop

The lexer tries to calculate 10^1111111111111 which will be a very large
number. This will take a long time.

The lexer should not try to calculate numbers from strings, as this
might fail and we do not want the lexer to give up, as no parsing and
semantic analysis will be done.

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 3 years ago
parent
commit
a1bb3c8b7e

+ 0 - 3
solang-parser/Cargo.toml

@@ -15,9 +15,6 @@ lalrpop = "0.19"
 
 [dependencies]
 lalrpop-util = "0.19"
-num-bigint = "0.4"
-num-traits = "0.2"
-num-rational = "0.4"
 phf = { version = "0.10", features = ["macros"] }
 unicode-xid = "0.2.0"
 itertools = "0.10"

+ 12 - 12
solang-parser/src/lexer.rs

@@ -189,13 +189,13 @@ impl<'input> fmt::Display for Token<'input> {
             Token::StringLiteral(s) => write!(f, "\"{}\"", s),
             Token::HexLiteral(hex) => write!(f, "{}", hex),
             Token::AddressLiteral(address) => write!(f, "{}", address),
-            Token::Number(base, exp) if exp.is_empty() => write!(f, "{}", base),
-            Token::Number(base, exp) => write!(f, "{}e{}", base, exp),
-            Token::RationalNumber(significand, mantissa, exp) if exp.is_empty() => {
-                write!(f, "{}.{}", significand, mantissa)
+            Token::Number(integer, exp) if exp.is_empty() => write!(f, "{}", integer),
+            Token::Number(integer, exp) => write!(f, "{}e{}", integer, exp),
+            Token::RationalNumber(integer, fraction, exp) if exp.is_empty() => {
+                write!(f, "{}.{}", integer, fraction)
             }
-            Token::RationalNumber(significand, mantissa, exp) => {
-                write!(f, "{}.{}e{}", significand, mantissa, exp)
+            Token::RationalNumber(integer, fraction, exp) => {
+                write!(f, "{}.{}e{}", integer, fraction, exp)
             }
             Token::HexNumber(n) => write!(f, "{}", n),
             Token::Uint(w) => write!(f, "uint{}", w),
@@ -678,21 +678,21 @@ impl<'input> Lexer<'input> {
         }
 
         if is_rational {
-            let significand = &self.input[start..=end_before_rational];
-            let mantissa = &self.input[rational_start..=rational_end];
-
+            let integer = &self.input[start..=end_before_rational];
+            let fraction = &self.input[rational_start..=rational_end];
             let exp = &self.input[exp_start..=end];
+
             return Ok((
                 start,
-                Token::RationalNumber(significand, mantissa, exp),
+                Token::RationalNumber(integer, fraction, exp),
                 end + 1,
             ));
         }
 
-        let base = &self.input[start..=old_end];
+        let integer = &self.input[start..=old_end];
         let exp = &self.input[exp_start..=end];
 
-        Ok((start, Token::Number(base, exp), end + 1))
+        Ok((start, Token::Number(integer, exp), end + 1))
     }
 
     fn string(

+ 5 - 8
solang-parser/src/pt.rs

@@ -1,8 +1,5 @@
 use std::fmt::{self, Display};
 
-use num_bigint::BigInt;
-use num_rational::BigRational;
-
 #[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Clone, Copy)]
 /// file no, start offset, end offset (in bytes)
 pub enum Loc {
@@ -407,8 +404,8 @@ pub enum Expression {
     AssignDivide(Loc, Box<Expression>, Box<Expression>),
     AssignModulo(Loc, Box<Expression>, Box<Expression>),
     BoolLiteral(Loc, bool),
-    NumberLiteral(Loc, BigInt),
-    RationalNumberLiteral(Loc, BigRational),
+    NumberLiteral(Loc, String, String),
+    RationalNumberLiteral(Loc, String, String, String),
     HexNumberLiteral(Loc, String),
     StringLiteral(Vec<StringLiteral>),
     Type(Loc, Type),
@@ -472,8 +469,8 @@ impl CodeLocation for Expression {
             | Expression::AssignDivide(loc, ..)
             | Expression::AssignModulo(loc, ..)
             | Expression::BoolLiteral(loc, _)
-            | Expression::NumberLiteral(loc, _)
-            | Expression::RationalNumberLiteral(loc, _)
+            | Expression::NumberLiteral(loc, ..)
+            | Expression::RationalNumberLiteral(loc, ..)
             | Expression::HexNumberLiteral(loc, _)
             | Expression::ArrayLiteral(loc, _)
             | Expression::List(loc, _)
@@ -696,7 +693,7 @@ pub struct YulBlock {
 #[derive(Debug, PartialEq, Clone)]
 pub enum YulExpression {
     BoolLiteral(Loc, bool, Option<Identifier>),
-    NumberLiteral(Loc, BigInt, Option<Identifier>),
+    NumberLiteral(Loc, String, String, Option<Identifier>),
     HexNumberLiteral(Loc, String, Option<Identifier>),
     HexStringLiteral(HexLiteral, Option<Identifier>),
     StringLiteral(StringLiteral, Option<Identifier>),

+ 8 - 92
solang-parser/src/solidity.lalrpop

@@ -1,8 +1,3 @@
-use std::str::FromStr;
-use num_bigint::{BigUint, BigInt};
-use num_traits::{Pow, Zero};
-use num_rational::BigRational;
-use std::ops::Mul;
 use lalrpop_util::ParseError;
 use super::pt::*;
 use super::box_option;
@@ -430,87 +425,17 @@ NoFunctionTyPrecedence0: Expression = {
     <SolNoErrorIdentifier> => Expression::Variable(<>),
     <l:@L> <e:Precedence0> <u:Unit> <r:@R> => Expression::Unit(Loc::File(file_no, l, r), Box::new(e), u),
     <l:@L> <n:number> <r:@R> => {
-        let base: String = n.0.chars().filter(|v| *v != '_').collect();
+        let integer: String = n.0.chars().filter(|v| *v != '_').collect();
         let exp: String = n.1.chars().filter(|v| *v != '_').collect();
 
-        let base = BigInt::from_str(&base).unwrap();
-
-        let n = if exp.is_empty() {
-            base
-        } else {
-            let b10 = BigInt::from_str("10").unwrap();
-
-            if exp.starts_with('-') {
-                let exp = b10.pow(BigUint::from_str(&exp[1..]).unwrap());
-                let res = BigRational::new(base, exp);
-
-                if res.is_integer() {
-                    res.to_integer()
-                } else {
-                    return Expression::RationalNumberLiteral(Loc::File(file_no, l, r), res);
-                }
-            } else {
-                let exp = b10.pow(BigUint::from_str(&exp).unwrap());
-
-                base.mul(exp)
-            }
-        };
-
-        Expression::NumberLiteral(Loc::File(file_no, l, r), n)
+        Expression::NumberLiteral(Loc::File(file_no, l, r), integer, exp)
     },
     <l:@L> <n:rational> <r:@R> => {
-        let mut significand: String = n.0.to_string();
-        let mantissa: String = n.1.to_string();
-        let exp: String = n.2.to_string();
-        let len = if mantissa.is_empty() {
-            0
-        } else {
-            mantissa.len()
-        };
-        let mut test = false;
-        if exp.starts_with("-") {
-            test = true;
-        }
-
-        let denominator = BigInt::from_str("10").unwrap().pow(BigUint::from(len as u64));
-        let zero_index = mantissa.chars().position(|c| c != '0').unwrap_or(usize::MAX);
-        let n =  if exp.is_empty() {
-            if significand.is_empty() || significand == "0" {
-                if zero_index < usize::MAX {
-                    BigRational::new(BigInt::from_str(&mantissa[zero_index..]).unwrap(), denominator)
-                } else {
-                    BigRational::from(BigInt::zero())
-                }
-            } else {
-                significand.push_str(&mantissa);
-                BigRational::new(BigInt::from_str(&significand).unwrap(), denominator)
-            }
-        } else {
-            if significand.is_empty() || significand == "0" {
-                if zero_index < usize::MAX {
-                    if test {
-                        let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp[1..]).unwrap());
-                        BigRational::new(BigInt::from_str(&mantissa[zero_index..]).unwrap(), denominator.mul(exp_result))
-                    } else {
-                        let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp).unwrap());
-                        BigRational::new(BigInt::from_str(&mantissa[zero_index..]).unwrap().mul(exp_result), denominator)
-                    }
-                } else {
-                    BigRational::from(BigInt::zero())
-                }
-            } else {
-                significand.push_str(&mantissa);
-                if test {
-                    let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp[1..]).unwrap());
-                    BigRational::new(BigInt::from_str(&significand).unwrap(), denominator.mul(exp_result))
-                } else {
-                    let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp).unwrap());
-                    BigRational::new(BigInt::from_str(&significand).unwrap().mul(exp_result), denominator)
-                }
-            }
-        };
+        let integer: String = n.0.chars().filter(|v| *v != '_').collect();
+        let fraction: String = n.1.chars().filter(|v| *v != '_').collect();
+        let exp: String = n.2.chars().filter(|v| *v != '_').collect();
 
-        Expression::RationalNumberLiteral(Loc::File(file_no, l, r), n)
+        Expression::RationalNumberLiteral(Loc::File(file_no, l, r), integer, fraction, exp)
     },
     <l:@L> <n:hexnumber> <r:@R> => {
         Expression::HexNumberLiteral(Loc::File(file_no, l, r), n.to_owned())
@@ -869,19 +794,10 @@ YulLiteral: YulExpression = {
     <a:@L> "true" <t_type:(":" <YulIdentifier>)?> <b:@R> => YulExpression::BoolLiteral(Loc::File(file_no, a, b), true, t_type),
     <a:@L> "false" <t_type:(":" <YulIdentifier>)?> <b:@R> => YulExpression::BoolLiteral(Loc::File(file_no, a, b), false, t_type),
     <l:@L> <n:number> <t_type:(":" <YulIdentifier>)?> <r:@R> => {
-        let base: String = n.0.chars().filter(|v| *v != '_').collect();
+        let integer: String = n.0.chars().filter(|v| *v != '_').collect();
         let exp: String = n.1.chars().filter(|v| *v != '_').collect();
 
-        let n = if exp.is_empty() {
-            BigInt::from_str(&base).unwrap()
-        } else {
-            let base = BigInt::from_str(&base).unwrap();
-            let exp = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp).unwrap());
-
-            base.mul(exp)
-        };
-
-        YulExpression::NumberLiteral(Loc::File(file_no, l, r), n, t_type)
+        YulExpression::NumberLiteral(Loc::File(file_no, l, r), integer, exp, t_type)
     },
     <l:@L> <n:hexnumber> <t_type:(":" <YulIdentifier>)?> <r:@R> => {
         YulExpression::HexNumberLiteral(Loc::File(file_no, l, r), n.to_owned(), t_type)

+ 10 - 11
solang-parser/src/test.rs

@@ -1,7 +1,6 @@
 use crate::lexer::Lexer;
 use crate::pt::*;
 use crate::solidity;
-use num_bigint::BigInt;
 
 #[test]
 fn parse_test() {
@@ -154,8 +153,8 @@ fn parse_test() {
                             name: "sum".to_string(),
                         })),
                         vec![
-                            Expression::NumberLiteral(Loc::File(0, 765, 766), 1.into()),
-                            Expression::NumberLiteral(Loc::File(0, 768, 769), 1.into()),
+                            Expression::NumberLiteral(Loc::File(0, 765, 766), "1".to_string(), "".to_string()),
+                            Expression::NumberLiteral(Loc::File(0, 768, 769), "1".to_string(), "".to_string()),
                         ],
                     ),
                     Some((
@@ -190,7 +189,7 @@ fn parse_test() {
                                         })),
                                         Box::new(Expression::NumberLiteral(
                                             Loc::File(0, 830, 831),
-                                            2.into(),
+                                            "2".to_string(), "".to_string(),
                                         )),
                                     )],
                                 ),
@@ -478,7 +477,7 @@ fn test_assembly_parser() {
                                     }],
                                     Some(YulExpression::NumberLiteral(
                                         Loc::File(0, 107, 108),
-                                        BigInt::from(0),
+                                        "0".to_string(), "".to_string(),
                                         None,
                                     )),
                                 ),
@@ -498,7 +497,7 @@ fn test_assembly_parser() {
                                             }],
                                             Some(YulExpression::NumberLiteral(
                                                 Loc::File(0, 148, 149),
-                                                BigInt::from(0),
+                                                "0".to_string(), "".to_string(),
                                                 None,
                                             )),
                                         )],
@@ -678,7 +677,7 @@ fn test_assembly_parser() {
                                         Loc::File(0, 510, 620),
                                         YulExpression::NumberLiteral(
                                             Loc::File(0, 515, 516),
-                                            BigInt::from(0),
+                                            "0".to_string(), "".to_string(),
                                             None,
                                         ),
                                         YulBlock {
@@ -693,12 +692,12 @@ fn test_assembly_parser() {
                                                     arguments: vec![
                                                         YulExpression::NumberLiteral(
                                                             Loc::File(0, 554, 555),
-                                                            BigInt::from(0),
+                                                            "0".to_string(), "".to_string(),
                                                             None,
                                                         ),
                                                         YulExpression::NumberLiteral(
                                                             Loc::File(0, 557, 558),
-                                                            BigInt::from(0),
+                                                            "0".to_string(), "".to_string(),
                                                             None,
                                                         ),
                                                     ],
@@ -802,7 +801,7 @@ fn test_assembly_parser() {
                                                                     arguments: vec![
                                                                         YulExpression::NumberLiteral(
                                                                             Loc::File(0, 924, 930),
-                                                                            BigInt::from(3),
+                                                                            "3".to_string(), "".to_string(),
                                                                             Some(Identifier {
                                                                                 loc: Loc::File(0, 926, 930),
                                                                                 name: "u256".to_string(),
@@ -810,7 +809,7 @@ fn test_assembly_parser() {
                                                                         ),
                                                                         YulExpression::NumberLiteral(
                                                                             Loc::File(0, 932, 938),
-                                                                            BigInt::from(2),
+                                                                            "2".to_string(), "".to_string(),
                                                                             Some(Identifier {
                                                                                 loc: Loc::File(0, 934, 938),
                                                                                 name: "u256".to_string(),

+ 228 - 87
src/sema/expression.rs

@@ -1,16 +1,3 @@
-use num_bigint::BigInt;
-use num_bigint::Sign;
-use num_traits::FromPrimitive;
-use num_traits::Num;
-use num_traits::One;
-use num_traits::Pow;
-use num_traits::ToPrimitive;
-use num_traits::Zero;
-use std::cmp;
-use std::cmp::Ordering;
-use std::collections::{BTreeMap, HashMap};
-use std::ops::{Add, Shl, Sub};
-
 use super::address::to_hexstr_eip55;
 use super::ast::{
     Builtin, BuiltinStruct, CallArgs, CallTy, Diagnostic, Expression, Function, Mutability,
@@ -30,8 +17,17 @@ use crate::sema::unused_variable::{
 };
 use crate::Target;
 use base58::{FromBase58, FromBase58Error};
+use num_bigint::{BigInt, Sign};
 use num_rational::BigRational;
+use num_traits::{FromPrimitive, Num, One, Pow, ToPrimitive, Zero};
 use solang_parser::pt::Loc;
+use std::{
+    cmp,
+    cmp::Ordering,
+    collections::{BTreeMap, HashMap},
+    ops::{Add, Mul, Shl, Sub},
+    str::FromStr,
+};
 
 impl RetrieveType for Expression {
     fn ty(&self) -> Type {
@@ -1314,6 +1310,142 @@ fn coerce_number(
     })
 }
 
+/// Resolve the given number literal, multiplied by value of unit
+fn number_literal(
+    loc: &pt::Loc,
+    integer: &str,
+    exp: &str,
+    ns: &Namespace,
+    unit: &BigInt,
+    diagnostics: &mut Vec<Diagnostic>,
+    resolve_to: ResolveTo,
+) -> Result<Expression, ()> {
+    let integer = BigInt::from_str(integer).unwrap();
+
+    let n = if exp.is_empty() {
+        integer
+    } else {
+        let base10 = BigInt::from_str("10").unwrap();
+
+        if let Some(abs_exp) = exp.strip_prefix('-') {
+            if let Ok(exp) = u8::from_str(abs_exp) {
+                let res = BigRational::new(integer, base10.pow(exp));
+
+                if res.is_integer() {
+                    res.to_integer()
+                } else {
+                    return Ok(Expression::RationalNumberLiteral(*loc, Type::Rational, res));
+                }
+            } else {
+                diagnostics.push(Diagnostic::error(
+                    *loc,
+                    format!("exponent '{}' too large", exp),
+                ));
+                return Err(());
+            }
+        } else if let Ok(exp) = u8::from_str(exp) {
+            integer.mul(base10.pow(exp))
+        } else {
+            diagnostics.push(Diagnostic::error(
+                *loc,
+                format!("exponent '{}' too large", exp),
+            ));
+            return Err(());
+        }
+    };
+
+    bigint_to_expression(loc, &n.mul(unit), ns, diagnostics, resolve_to)
+}
+
+/// Resolve the given rational number literal, multiplied by value of unit
+fn rational_number_literal(
+    loc: &pt::Loc,
+    integer: &str,
+    fraction: &str,
+    exp: &str,
+    unit: &BigInt,
+    ns: &Namespace,
+    diagnostics: &mut Vec<Diagnostic>,
+    resolve_to: ResolveTo,
+) -> Result<Expression, ()> {
+    let mut integer = integer.to_owned();
+    let len = fraction.len();
+    let exp_negative = exp.starts_with('-');
+
+    let denominator = BigInt::from_str("10").unwrap().pow(len);
+    let zero_index = fraction
+        .chars()
+        .position(|c| c != '0')
+        .unwrap_or(usize::MAX);
+    let n = if exp.is_empty() {
+        if integer.is_empty() || integer == "0" {
+            if zero_index < usize::MAX {
+                BigRational::new(
+                    BigInt::from_str(&fraction[zero_index..]).unwrap(),
+                    denominator,
+                )
+            } else {
+                BigRational::from(BigInt::zero())
+            }
+        } else {
+            integer.push_str(fraction);
+            BigRational::new(BigInt::from_str(&integer).unwrap(), denominator)
+        }
+    } else {
+        let exp = if let Ok(exp) = u8::from_str(if exp_negative { &exp[1..] } else { exp }) {
+            exp
+        } else {
+            diagnostics.push(Diagnostic::error(
+                *loc,
+                format!("exponent '{}' too large", exp),
+            ));
+            return Err(());
+        };
+        let exp_result = BigInt::from_str("10").unwrap().pow(exp);
+
+        if integer.is_empty() || integer == "0" {
+            if zero_index < usize::MAX {
+                if exp_negative {
+                    BigRational::new(
+                        BigInt::from_str(&fraction[zero_index..]).unwrap(),
+                        denominator.mul(exp_result),
+                    )
+                } else {
+                    BigRational::new(
+                        BigInt::from_str(&fraction[zero_index..])
+                            .unwrap()
+                            .mul(exp_result),
+                        denominator,
+                    )
+                }
+            } else {
+                BigRational::from(BigInt::zero())
+            }
+        } else {
+            integer.push_str(fraction);
+            if exp_negative {
+                BigRational::new(
+                    BigInt::from_str(&integer).unwrap(),
+                    denominator.mul(exp_result),
+                )
+            } else {
+                BigRational::new(
+                    BigInt::from_str(&integer).unwrap().mul(exp_result),
+                    denominator,
+                )
+            }
+        }
+    };
+
+    let res = n.mul(unit);
+
+    if res.is_integer() {
+        bigint_to_expression(loc, &res.to_integer(), ns, diagnostics, resolve_to)
+    } else {
+        Ok(Expression::RationalNumberLiteral(*loc, Type::Rational, res))
+    }
+}
+
 /// Try to convert a BigInt into a Expression::NumberLiteral. This checks for sign,
 /// width and creates to correct Type.
 pub fn bigint_to_expression(
@@ -1414,33 +1546,6 @@ pub fn bigint_to_expression(
     }
 }
 
-/// Try to convert a Bigfloat into a Expression::RationalNumberLiteral. This checks for sign,
-/// width and creates to correct Type.
-pub fn bigdecimal_to_expression(
-    loc: &pt::Loc,
-    n: &BigRational,
-    ns: &Namespace,
-    diagnostics: &mut Vec<Diagnostic>,
-    resolve_to: ResolveTo,
-) -> Result<Expression, ()> {
-    if let ResolveTo::Type(resolve_to) = resolve_to {
-        if !resolve_to.is_rational() {
-            diagnostics.push(Diagnostic::error(
-                *loc,
-                format!("expected '{}', found rational", resolve_to.to_string(ns)),
-            ));
-            return Err(());
-        } else {
-            return Ok(Expression::RationalNumberLiteral(
-                *loc,
-                resolve_to.clone(),
-                n.clone(),
-            ));
-        };
-    }
-    Err(())
-}
-
 /// Compare two mutability levels
 pub fn compatible_mutability(left: &Mutability, right: &Mutability) -> bool {
     matches!(
@@ -1508,14 +1613,27 @@ pub fn expression(
             Ok(string_literal(v, context.file_no, diagnostics, resolve_to))
         }
         pt::Expression::HexLiteral(v) => hex_literal(v, diagnostics),
-        pt::Expression::NumberLiteral(loc, b) => {
-            bigint_to_expression(loc, b, ns, diagnostics, resolve_to)
+        pt::Expression::NumberLiteral(loc, integer, exp) => number_literal(
+            loc,
+            integer,
+            exp,
+            ns,
+            &BigInt::one(),
+            diagnostics,
+            resolve_to,
+        ),
+        pt::Expression::RationalNumberLiteral(loc, integer, fraction, exp) => {
+            rational_number_literal(
+                loc,
+                integer,
+                fraction,
+                exp,
+                &BigInt::one(),
+                ns,
+                diagnostics,
+                resolve_to,
+            )
         }
-        pt::Expression::RationalNumberLiteral(loc, b) => Ok(Expression::RationalNumberLiteral(
-            *loc,
-            Type::Rational,
-            b.clone(),
-        )),
         pt::Expression::HexNumberLiteral(loc, n) => {
             hex_number_literal(loc, n, ns, diagnostics, resolve_to)
         }
@@ -1675,9 +1793,15 @@ pub fn expression(
             Ok(Expression::Complement(*loc, expr_ty, Box::new(expr)))
         }
         pt::Expression::UnaryMinus(loc, e) => match e.as_ref() {
-            pt::Expression::NumberLiteral(_, n) => {
-                bigint_to_expression(loc, &-n, ns, diagnostics, resolve_to)
-            }
+            pt::Expression::NumberLiteral(_, integer, exp) => number_literal(
+                loc,
+                integer,
+                exp,
+                ns,
+                &BigInt::from(-1),
+                diagnostics,
+                resolve_to,
+            ),
             pt::Expression::HexNumberLiteral(_, v) => {
                 // a hex literal with a minus before it cannot be an address literal or a bytesN value
                 let s: String = v.chars().skip(2).filter(|v| *v != '_').collect();
@@ -1686,8 +1810,17 @@ pub fn expression(
 
                 bigint_to_expression(loc, &-n, ns, diagnostics, resolve_to)
             }
-            pt::Expression::RationalNumberLiteral(_, r) => {
-                bigdecimal_to_expression(loc, &-r, ns, diagnostics, resolve_to)
+            pt::Expression::RationalNumberLiteral(loc, integer, fraction, exp) => {
+                rational_number_literal(
+                    loc,
+                    integer,
+                    fraction,
+                    exp,
+                    &BigInt::from(-1),
+                    ns,
+                    diagnostics,
+                    resolve_to,
+                )
             }
             e => {
                 let expr = expression(e, context, ns, symtable, diagnostics, resolve_to)?;
@@ -1697,8 +1830,8 @@ pub fn expression(
 
                 if let Expression::NumberLiteral(_, _, n) = expr {
                     bigint_to_expression(loc, &-n, ns, diagnostics, resolve_to)
-                } else if let Expression::RationalNumberLiteral(_, _, r) = expr {
-                    bigdecimal_to_expression(loc, &-r, ns, diagnostics, resolve_to)
+                } else if let Expression::RationalNumberLiteral(_, ty, r) = expr {
+                    Ok(Expression::RationalNumberLiteral(*loc, ty, -r))
                 } else {
                     get_int_length(&expr_type, loc, false, ns, diagnostics)?;
 
@@ -1937,52 +2070,60 @@ pub fn expression(
             Err(())
         }
         pt::Expression::Unit(loc, expr, unit) => {
-            let n = match expr.as_ref() {
-                pt::Expression::NumberLiteral(_, n) => n,
+            match unit {
+                pt::Unit::Wei(loc) | pt::Unit::Gwei(loc) | pt::Unit::Ether(loc)
+                    if ns.target != crate::Target::Ewasm =>
+                {
+                    diagnostics.push(Diagnostic::warning(
+                        *loc,
+                        "ethereum currency unit used while not targetting ethereum".to_owned(),
+                    ));
+                }
+                _ => (),
+            }
+
+            let unit = match unit {
+                pt::Unit::Seconds(_) => BigInt::from(1),
+                pt::Unit::Minutes(_) => BigInt::from(60),
+                pt::Unit::Hours(_) => BigInt::from(60 * 60),
+                pt::Unit::Days(_) => BigInt::from(60 * 60 * 24),
+                pt::Unit::Weeks(_) => BigInt::from(60 * 60 * 24 * 7),
+                pt::Unit::Wei(_) => BigInt::from(1),
+                pt::Unit::Gwei(_) => BigInt::from(10).pow(9u32),
+                pt::Unit::Ether(_) => BigInt::from(10).pow(18u32),
+            };
+
+            match expr.as_ref() {
+                pt::Expression::NumberLiteral(_, integer, exp) => {
+                    number_literal(loc, integer, exp, ns, &unit, diagnostics, resolve_to)
+                }
+                pt::Expression::RationalNumberLiteral(_, significant, mantissa, exp) => {
+                    rational_number_literal(
+                        loc,
+                        significant,
+                        mantissa,
+                        exp,
+                        &unit,
+                        ns,
+                        diagnostics,
+                        resolve_to,
+                    )
+                }
                 pt::Expression::HexNumberLiteral(loc, _) => {
                     diagnostics.push(Diagnostic::error(
                         *loc,
                         "hexadecimal numbers cannot be used with unit denominations".to_owned(),
                     ));
-                    return Err(());
+                    Err(())
                 }
                 _ => {
                     diagnostics.push(Diagnostic::error(
                         *loc,
                         "unit denominations can only be used with number literals".to_owned(),
                     ));
-                    return Err(());
-                }
-            };
-
-            match unit {
-                pt::Unit::Wei(loc) | pt::Unit::Gwei(loc) | pt::Unit::Ether(loc)
-                    if ns.target != crate::Target::Ewasm =>
-                {
-                    diagnostics.push(Diagnostic::warning(
-                        *loc,
-                        "ethereum currency unit used while not targetting ethereum".to_owned(),
-                    ));
+                    Err(())
                 }
-                _ => (),
             }
-
-            bigint_to_expression(
-                loc,
-                &(n * match unit {
-                    pt::Unit::Seconds(_) => BigInt::from(1),
-                    pt::Unit::Minutes(_) => BigInt::from(60),
-                    pt::Unit::Hours(_) => BigInt::from(60 * 60),
-                    pt::Unit::Days(_) => BigInt::from(60 * 60 * 24),
-                    pt::Unit::Weeks(_) => BigInt::from(60 * 60 * 24 * 7),
-                    pt::Unit::Wei(_) => BigInt::from(1),
-                    pt::Unit::Gwei(_) => BigInt::from(10).pow(9u32),
-                    pt::Unit::Ether(_) => BigInt::from(10).pow(18u32),
-                }),
-                ns,
-                diagnostics,
-                resolve_to,
-            )
         }
         pt::Expression::This(loc) => match context.contract_no {
             Some(contract_no) => Ok(Expression::Builtin(

+ 47 - 6
src/sema/yul/expression.rs

@@ -9,10 +9,12 @@ use crate::sema::yul::types::{
 };
 use crate::sema::yul::unused_variable::{assigned_variable, used_variable};
 use num_bigint::{BigInt, Sign};
-use num_traits::Num;
+use num_rational::BigRational;
+use num_traits::{Num, Pow};
 use solang_parser::diagnostics::{ErrorType, Level};
 use solang_parser::pt::{CodeLocation, Identifier, Loc, StorageLocation, YulFunctionCall};
 use solang_parser::{pt, Diagnostic};
+use std::{ops::Mul, str::FromStr};
 
 /// Given a keyword, returns the suffix it represents in YUL
 fn get_suffix_from_string(suffix_name: &str) -> Option<YulSuffix> {
@@ -37,8 +39,8 @@ pub(crate) fn resolve_yul_expression(
     match expr {
         pt::YulExpression::BoolLiteral(loc, value, ty) => resolve_bool_literal(loc, value, ty, ns),
 
-        pt::YulExpression::NumberLiteral(loc, value, ty) => {
-            resolve_number_literal(loc, value, ty, ns)
+        pt::YulExpression::NumberLiteral(loc, base, exp, ty) => {
+            resolve_number_literal(loc, base, exp, ty, ns)
         }
 
         pt::YulExpression::HexNumberLiteral(loc, value, ty) => {
@@ -115,10 +117,49 @@ fn resolve_bool_literal(
 
 fn resolve_number_literal(
     loc: &pt::Loc,
-    value: &BigInt,
+    integer: &str,
+    exp: &str,
     ty: &Option<pt::Identifier>,
     ns: &mut Namespace,
 ) -> Result<YulExpression, ()> {
+    let integer = BigInt::from_str(integer).unwrap();
+
+    let value = if exp.is_empty() {
+        integer
+    } else {
+        let base10 = BigInt::from_str("10").unwrap();
+
+        if let Some(abs_exp) = exp.strip_prefix('-') {
+            if let Ok(exp) = u8::from_str(abs_exp) {
+                let res = BigRational::new(integer, base10.pow(exp));
+
+                if res.is_integer() {
+                    res.to_integer()
+                } else {
+                    ns.diagnostics.push(Diagnostic::error(
+                        *loc,
+                        "rational numbers not permitted".to_string(),
+                    ));
+                    return Err(());
+                }
+            } else {
+                ns.diagnostics.push(Diagnostic::error(
+                    *loc,
+                    format!("exponent '{}' too large", exp),
+                ));
+                return Err(());
+            }
+        } else if let Ok(exp) = u8::from_str(exp) {
+            integer.mul(base10.pow(exp))
+        } else {
+            ns.diagnostics.push(Diagnostic::error(
+                *loc,
+                format!("exponent '{}' too large", exp),
+            ));
+            return Err(());
+        }
+    };
+
     let new_type = if let Some(type_id) = ty {
         if let Some(asm_type) = get_type_from_string(&type_id.name) {
             if matches!(asm_type, Type::Uint(_)) && matches!(value.sign(), Sign::Minus) {
@@ -140,7 +181,7 @@ fn resolve_number_literal(
             return Err(());
         }
     } else {
-        get_type_from_big_int(value)
+        get_type_from_big_int(&value)
     };
 
     let type_size = new_type.get_type_size();
@@ -163,7 +204,7 @@ fn resolve_number_literal(
         });
     }
 
-    Ok(YulExpression::NumberLiteral(*loc, value.clone(), new_type))
+    Ok(YulExpression::NumberLiteral(*loc, value, new_type))
 }
 
 fn resolve_hex_literal(

+ 7 - 5
src/sema/yul/tests/expression.rs

@@ -11,7 +11,6 @@ use crate::sema::yul::functions::FunctionsTable;
 use crate::sema::yul::tests::parse;
 use crate::{ast, Target};
 use num_bigint::BigInt;
-use num_traits::FromPrimitive;
 use solang_parser::pt;
 use solang_parser::pt::{
     ContractTy, HexLiteral, Identifier, Loc, StorageLocation, StringLiteral, Visibility,
@@ -84,7 +83,8 @@ fn resolve_number_literal() {
     let mut ns = Namespace::new(Target::Solana);
     let expr = pt::YulExpression::NumberLiteral(
         loc,
-        BigInt::from_u128(0xffffffffffffffffff).unwrap(),
+        "4722366482869645213695".to_string(),
+        "".to_string(),
         Some(Identifier {
             loc,
             name: "u64".to_string(),
@@ -101,7 +101,8 @@ fn resolve_number_literal() {
     ns.diagnostics = Diagnostics::default();
     let expr = pt::YulExpression::NumberLiteral(
         loc,
-        BigInt::from_i32(-50).unwrap(),
+        "-50".to_string(),
+        "".to_string(),
         Some(Identifier {
             loc,
             name: "u128".to_string(),
@@ -116,7 +117,7 @@ fn resolve_number_literal() {
     );
 
     ns.diagnostics = Diagnostics::default();
-    let expr = pt::YulExpression::NumberLiteral(loc, BigInt::from(20), None);
+    let expr = pt::YulExpression::NumberLiteral(loc, "20".to_string(), "".to_string(), None);
     let parsed = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(parsed.is_ok());
     assert!(ns.diagnostics.is_empty());
@@ -752,7 +753,8 @@ fn check_arguments() {
             },
             arguments: vec![pt::YulExpression::NumberLiteral(
                 loc,
-                BigInt::from(23),
+                "23".to_string(),
+                "".to_string(),
                 None,
             )],
         }))],

+ 30 - 0
tests/contract_testcases/solana/large_exponent.dot

@@ -0,0 +1,30 @@
+strict digraph "tests/contract_testcases/solana/large_exponent.sol" {
+	contract [label="contract C\ntests/contract_testcases/solana/large_exponent.sol:1:1-12"]
+	var [label="variable a\nvisibility internal\nconstant\ntests/contract_testcases/solana/large_exponent.sol:2:6-31"]
+	var_4 [label="variable b\nvisibility internal\nconstant\ntests/contract_testcases/solana/large_exponent.sol:3:6-34"]
+	var_5 [label="variable c\nvisibility internal\nconstant\ntests/contract_testcases/solana/large_exponent.sol:4:6-33"]
+	f [label="function f\ncontract: C\ntests/contract_testcases/solana/large_exponent.sol:5:6-26\nsignature f()\nvisibility private\nmutability nonpayable"]
+	inline_assembly [label="inline assembly\ntests/contract_testcases/solana/large_exponent.sol:6:2-8:3"]
+	g [label="function g\ncontract: C\ntests/contract_testcases/solana/large_exponent.sol:10:6-26\nsignature g()\nvisibility private\nmutability nonpayable"]
+	inline_assembly_9 [label="inline assembly\ntests/contract_testcases/solana/large_exponent.sol:11:2-13:3"]
+	diagnostic [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/large_exponent.sol:1:1-12"]
+	diagnostic_12 [label="literal 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 is too large to fit into type 'int256'\nlevel Error\ntests/contract_testcases/solana/large_exponent.sol:2:26-31"]
+	diagnostic_13 [label="exponent '-65535' too large\nlevel Error\ntests/contract_testcases/solana/large_exponent.sol:3:26-34"]
+	diagnostic_14 [label="exponent '65537' too large\nlevel Error\ntests/contract_testcases/solana/large_exponent.sol:4:26-33"]
+	diagnostic_15 [label="exponent '65537' too large\nlevel Error\ntests/contract_testcases/solana/large_exponent.sol:7:12-19"]
+	diagnostic_16 [label="rational numbers not permitted\nlevel Error\ntests/contract_testcases/solana/large_exponent.sol:12:12-16"]
+	contracts -> contract
+	contract -> var [label="variable"]
+	contract -> var_4 [label="variable"]
+	contract -> var_5 [label="variable"]
+	contract -> f [label="function"]
+	f -> inline_assembly [label="body"]
+	contract -> g [label="function"]
+	g -> inline_assembly_9 [label="body"]
+	diagnostics -> diagnostic [label="Debug"]
+	diagnostics -> diagnostic_12 [label="Error"]
+	diagnostics -> diagnostic_13 [label="Error"]
+	diagnostics -> diagnostic_14 [label="Error"]
+	diagnostics -> diagnostic_15 [label="Error"]
+	diagnostics -> diagnostic_16 [label="Error"]
+}

+ 16 - 0
tests/contract_testcases/solana/large_exponent.sol

@@ -0,0 +1,16 @@
+contract C {
+     int256 constant a = 1e255;
+     int256 constant b = 1e-65535;
+     int256 constant c = 1e65537;
+     function f() private {
+	assembly {
+		let x := 1e65537
+	}
+     }
+     function g() private {
+	assembly {
+		let x := 1e-1
+	}
+     }
+
+}