diff --git a/src/interpreter/env.rs b/src/interpreter/env.rs index fb20d5e..06c0407 100644 --- a/src/interpreter/env.rs +++ b/src/interpreter/env.rs @@ -1,4 +1,5 @@ use futures_util::lock::Mutex; +use solang_parser::pt::{Expression, Identifier}; use std::{ collections::{HashMap, HashSet}, sync::Arc, @@ -12,12 +13,12 @@ use alloy::{ signers::{ledger::HDPath, local::PrivateKeySigner, Signature}, transports::http::{Client, Http}, }; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use coins_ledger::{transports::LedgerAsync, Ledger}; use crate::{interpreter::Config, vendor::ledger_signer::LedgerSigner}; -use super::{types::Type, Value}; +use super::{evaluate_expression, types::Type, Value}; pub struct Env { variables: Vec>, @@ -173,6 +174,26 @@ impl Env { scope.insert(name.to_string(), value); } + pub async fn init_variable( + &mut self, + name: &Option, + type_: &Expression, + initializer: &Option, + ) -> Result<()> { + let id = name.clone().ok_or(anyhow!("invalid declaration"))?.name; + let type_ = match evaluate_expression(self, Box::new(type_.clone())).await? { + Value::TypeObject(t) => t, + v => bail!("invalid type for variable, expected type, got {}", v), + }; + let value = if let Some(e) = initializer { + evaluate_expression(self, Box::new(e.clone())).await? + } else { + type_.default_value()? + }; + self.set_var(&id, value); + Ok(()) + } + fn set_wallet(&mut self, signer: S) -> Result<()> where S: TxSigner + Send + Sync + 'static, diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 0d25060..f155e27 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -137,13 +137,8 @@ pub async fn evaluate_contract_part( env.set_var(&func.name, Value::Func(Function::UserDefined(func.clone()))); } ContractPart::VariableDefinition(def) => { - let id = def.name.clone().ok_or(anyhow!("invalid declaration"))?.name; - if let Some(expr) = &def.initializer { - let result = evaluate_expression(env, Box::new(expr.clone())).await?; - env.set_var(&id, result.clone()); - } else { - bail!("declarations need rhs") - } + env.init_variable(&def.name, &def.ty, &def.initializer) + .await?; } v => bail!("{} not supported", v), } @@ -246,18 +241,8 @@ pub fn evaluate_statement( } Statement::VariableDefinition(_, var, expr) => { - let id = var - .name - .clone() - .ok_or(anyhow!("invalid declaration {}", stmt))? - .name; - if let Some(e) = expr { - let result = evaluate_expression(env, Box::new(e.clone())).await?; - env.set_var(&id, result.clone()); - Ok(StatementResult::Empty) - } else { - bail!("declarations need rhs") - } + env.init_variable(&var.name, &var.ty, expr).await?; + Ok(StatementResult::Empty) } stmt => bail!("statement {:?} not supported", stmt), } diff --git a/src/interpreter/types.rs b/src/interpreter/types.rs index 60004f8..5800c12 100644 --- a/src/interpreter/types.rs +++ b/src/interpreter/types.rs @@ -253,6 +253,36 @@ impl TryFrom for DynSolType { } impl Type { + pub fn default_value(&self) -> Result { + let value = match self { + Type::Null => Value::Null, + Type::Address => Value::Addr(Address::ZERO), + Type::Bool => Value::Bool(false), + Type::Int(size) => Value::Int(I256::ZERO, *size), + Type::Uint(size) => Value::Uint(U256::ZERO, *size), + Type::FixBytes(size) => Value::FixBytes(B256::default(), *size), + Type::Bytes => Value::Bytes(vec![]), + Type::String => Value::Str("".to_string()), + Type::Array(_) => Value::Array(vec![]), + Type::FixedArray(t, size) => Value::Array(vec![t.default_value()?; *size]), + Type::NamedTuple(_, fields) => Value::NamedTuple( + "".to_string(), + fields + .iter() + .map(|(k, v)| v.default_value().map(|v_| (k.clone(), v_))) + .collect::>>()?, + ), + Type::Tuple(types) => Value::Array( + types + .iter() + .map(|t| t.default_value()) + .collect::>>()?, + ), + _ => bail!("cannot get default value for type {}", self), + }; + Ok(value) + } + pub fn is_int(&self) -> bool { matches!(self, Type::Int(_) | Type::Uint(_)) }