use std::rc::Rc;
use crate::ast::constant::TryExtractFromError;
use crate::ast::expr::Expr;
use crate::ast::value::Value;
use crate::chain::ergo_box::RegisterIdOutOfBounds;
use crate::sigma_protocol::sigma_boolean::SigmaBoolean;
use cost_accum::CostAccumulator;
use thiserror::Error;
use self::context::Context;
use self::cost_accum::CostError;
use self::env::Env;
pub(crate) mod context;
pub(crate) mod cost_accum;
pub(crate) mod costs;
pub(crate) mod env;
pub(crate) mod expr;
pub(crate) mod global_vars;
pub(crate) mod method_call;
pub(crate) mod property_call;
#[derive(Error, PartialEq, Eq, Debug, Clone)]
pub enum EvalError {
#[error("Only boolean or SigmaBoolean is a valid result expr type")]
InvalidResultType,
#[error("unexpected Expr: {0:?}")]
UnexpectedExpr(String),
#[error("Error on cost calculation: {0:?}")]
CostError(#[from] CostError),
#[error("Unexpected value type: {0:?}")]
TryExtractFrom(#[from] TryExtractFromError),
#[error("Not found: {0}")]
NotFound(String),
#[error("{0:?}")]
RegisterIdOutOfBounds(#[from] RegisterIdOutOfBounds),
#[error("unexpected value: {0:?}")]
UnexpectedValue(String),
}
pub struct ReductionResult {
pub sigma_prop: SigmaBoolean,
pub cost: u64,
}
pub trait Evaluator {
fn reduce_to_crypto(
&self,
expr: &Expr,
env: &Env,
ctx: Rc<Context>,
) -> Result<ReductionResult, EvalError> {
let cost_accum = CostAccumulator::new(0, None);
let mut ectx = EvalContext::new(ctx, cost_accum);
expr.eval(env, &mut ectx)
.and_then(|v| -> Result<ReductionResult, EvalError> {
match v {
Value::Boolean(b) => Ok(ReductionResult {
sigma_prop: SigmaBoolean::TrivialProp(b),
cost: 0,
}),
Value::SigmaProp(sp) => Ok(ReductionResult {
sigma_prop: sp.value().clone(),
cost: 0,
}),
_ => Err(EvalError::InvalidResultType),
}
})
}
}
pub struct EvalContext {
pub ctx: Rc<Context>,
pub cost_accum: CostAccumulator,
}
impl EvalContext {
pub fn new(ctx: Rc<Context>, cost_accum: CostAccumulator) -> Self {
EvalContext { ctx, cost_accum }
}
}
pub trait Evaluable {
fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result<Value, EvalError>;
}
#[cfg(test)]
pub mod tests {
use crate::ast::constant::TryExtractFrom;
use crate::ast::constant::TryExtractInto;
use super::env::Env;
use super::*;
pub fn eval_out<T: TryExtractFrom<Value>>(expr: &Expr, ctx: Rc<Context>) -> T {
let cost_accum = CostAccumulator::new(0, None);
let mut ectx = EvalContext::new(ctx, cost_accum);
expr.eval(&Env::empty(), &mut ectx)
.unwrap()
.try_extract_into::<T>()
.unwrap()
}
}