eval.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // SPDX-License-Identifier: Apache-2.0
  2. use num_bigint::BigInt;
  3. use num_bigint::Sign;
  4. use num_rational::BigRational;
  5. use num_traits::One;
  6. use num_traits::ToPrimitive;
  7. use num_traits::Zero;
  8. use super::ast::{Diagnostic, Expression, Namespace};
  9. use solang_parser::pt;
  10. use solang_parser::pt::CodeLocation;
  11. /// Resolve an expression where a compile-time constant is expected
  12. pub fn eval_const_number(
  13. expr: &Expression,
  14. ns: &Namespace,
  15. ) -> Result<(pt::Loc, BigInt), Diagnostic> {
  16. match expr {
  17. Expression::Add(loc, _, _, l, r) => Ok((
  18. *loc,
  19. eval_const_number(l, ns)?.1 + eval_const_number(r, ns)?.1,
  20. )),
  21. Expression::Subtract(loc, _, _, l, r) => Ok((
  22. *loc,
  23. eval_const_number(l, ns)?.1 - eval_const_number(r, ns)?.1,
  24. )),
  25. Expression::Multiply(loc, _, _, l, r) => Ok((
  26. *loc,
  27. eval_const_number(l, ns)?.1 * eval_const_number(r, ns)?.1,
  28. )),
  29. Expression::Divide(loc, _, l, r) => {
  30. let divisor = eval_const_number(r, ns)?.1;
  31. if divisor.is_zero() {
  32. Err(Diagnostic::error(*loc, "divide by zero".to_string()))
  33. } else {
  34. Ok((*loc, eval_const_number(l, ns)?.1 / divisor))
  35. }
  36. }
  37. Expression::Modulo(loc, _, l, r) => {
  38. let divisor = eval_const_number(r, ns)?.1;
  39. if divisor.is_zero() {
  40. Err(Diagnostic::error(*loc, "divide by zero".to_string()))
  41. } else {
  42. Ok((*loc, eval_const_number(l, ns)?.1 % divisor))
  43. }
  44. }
  45. Expression::BitwiseAnd(loc, _, l, r) => Ok((
  46. *loc,
  47. eval_const_number(l, ns)?.1 & eval_const_number(r, ns)?.1,
  48. )),
  49. Expression::BitwiseOr(loc, _, l, r) => Ok((
  50. *loc,
  51. eval_const_number(l, ns)?.1 | eval_const_number(r, ns)?.1,
  52. )),
  53. Expression::BitwiseXor(loc, _, l, r) => Ok((
  54. *loc,
  55. eval_const_number(l, ns)?.1 ^ eval_const_number(r, ns)?.1,
  56. )),
  57. Expression::Power(loc, _, _, base, exp) => {
  58. let b = eval_const_number(base, ns)?.1;
  59. let mut e = eval_const_number(exp, ns)?.1;
  60. if e.sign() == Sign::Minus {
  61. Err(Diagnostic::error(
  62. expr.loc(),
  63. "power cannot take negative number as exponent".to_string(),
  64. ))
  65. } else if e.sign() == Sign::NoSign {
  66. Ok((*loc, BigInt::one()))
  67. } else {
  68. let mut res = b.clone();
  69. e -= BigInt::one();
  70. while e.sign() == Sign::Plus {
  71. res *= b.clone();
  72. e -= BigInt::one();
  73. }
  74. Ok((*loc, res))
  75. }
  76. }
  77. Expression::ShiftLeft(loc, _, left, right) => {
  78. let l = eval_const_number(left, ns)?.1;
  79. let r = eval_const_number(right, ns)?.1;
  80. let r = match r.to_usize() {
  81. Some(r) => r,
  82. None => {
  83. return Err(Diagnostic::error(
  84. expr.loc(),
  85. format!("cannot left shift by {}", r),
  86. ));
  87. }
  88. };
  89. Ok((*loc, l << r))
  90. }
  91. Expression::ShiftRight(loc, _, left, right, _) => {
  92. let l = eval_const_number(left, ns)?.1;
  93. let r = eval_const_number(right, ns)?.1;
  94. let r = match r.to_usize() {
  95. Some(r) => r,
  96. None => {
  97. return Err(Diagnostic::error(
  98. expr.loc(),
  99. format!("cannot right shift by {}", r),
  100. ));
  101. }
  102. };
  103. Ok((*loc, l >> r))
  104. }
  105. Expression::NumberLiteral(loc, _, n) => Ok((*loc, n.clone())),
  106. Expression::ZeroExt(loc, _, n) => Ok((*loc, eval_const_number(n, ns)?.1)),
  107. Expression::SignExt(loc, _, n) => Ok((*loc, eval_const_number(n, ns)?.1)),
  108. Expression::Cast(loc, _, n) => Ok((*loc, eval_const_number(n, ns)?.1)),
  109. Expression::Not(loc, n) => Ok((*loc, !eval_const_number(n, ns)?.1)),
  110. Expression::Complement(loc, _, n) => Ok((*loc, !eval_const_number(n, ns)?.1)),
  111. Expression::UnaryMinus(loc, _, n) => Ok((*loc, -eval_const_number(n, ns)?.1)),
  112. Expression::ConstantVariable(_, _, Some(contract_no), var_no) => {
  113. let expr = ns.contracts[*contract_no].variables[*var_no]
  114. .initializer
  115. .as_ref()
  116. .unwrap()
  117. .clone();
  118. eval_const_number(&expr, ns)
  119. }
  120. Expression::ConstantVariable(_, _, None, var_no) => {
  121. let expr = ns.constants[*var_no].initializer.as_ref().unwrap().clone();
  122. eval_const_number(&expr, ns)
  123. }
  124. _ => Err(Diagnostic::error(
  125. expr.loc(),
  126. "expression not allowed in constant number expression".to_string(),
  127. )),
  128. }
  129. }
  130. /// Resolve an expression where a compile-time constant(rational) is expected
  131. pub fn eval_const_rational(
  132. expr: &Expression,
  133. ns: &Namespace,
  134. ) -> Result<(pt::Loc, BigRational), Diagnostic> {
  135. match expr {
  136. Expression::Add(loc, _, _, l, r) => Ok((
  137. *loc,
  138. eval_const_rational(l, ns)?.1 + eval_const_rational(r, ns)?.1,
  139. )),
  140. Expression::Subtract(loc, _, _, l, r) => Ok((
  141. *loc,
  142. eval_const_rational(l, ns)?.1 - eval_const_rational(r, ns)?.1,
  143. )),
  144. Expression::Multiply(loc, _, _, l, r) => Ok((
  145. *loc,
  146. eval_const_rational(l, ns)?.1 * eval_const_rational(r, ns)?.1,
  147. )),
  148. Expression::Divide(loc, _, l, r) => {
  149. let divisor = eval_const_rational(r, ns)?.1;
  150. if divisor.is_zero() {
  151. Err(Diagnostic::error(*loc, "divide by zero".to_string()))
  152. } else {
  153. Ok((*loc, eval_const_rational(l, ns)?.1 / divisor))
  154. }
  155. }
  156. Expression::Modulo(loc, _, l, r) => {
  157. let divisor = eval_const_rational(r, ns)?.1;
  158. if divisor.is_zero() {
  159. Err(Diagnostic::error(*loc, "divide by zero".to_string()))
  160. } else {
  161. Ok((*loc, eval_const_rational(l, ns)?.1 % divisor))
  162. }
  163. }
  164. Expression::NumberLiteral(loc, _, n) => Ok((*loc, BigRational::from_integer(n.clone()))),
  165. Expression::RationalNumberLiteral(loc, _, n) => Ok((*loc, n.clone())),
  166. Expression::Cast(loc, _, n) => Ok((*loc, eval_const_rational(n, ns)?.1)),
  167. Expression::UnaryMinus(loc, _, n) => Ok((*loc, -eval_const_rational(n, ns)?.1)),
  168. Expression::ConstantVariable(_, _, Some(contract_no), var_no) => {
  169. let expr = ns.contracts[*contract_no].variables[*var_no]
  170. .initializer
  171. .as_ref()
  172. .unwrap()
  173. .clone();
  174. eval_const_rational(&expr, ns)
  175. }
  176. Expression::ConstantVariable(_, _, None, var_no) => {
  177. let expr = ns.constants[*var_no].initializer.as_ref().unwrap().clone();
  178. eval_const_rational(&expr, ns)
  179. }
  180. _ => Err(Diagnostic::error(
  181. expr.loc(),
  182. "expression not allowed in constant rational number expression".to_string(),
  183. )),
  184. }
  185. }