From 2428e3e3194a554495ebaf39c7ef44d7f80cc1f0 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 17 Jul 2023 16:28:30 +0300 Subject: [PATCH 01/74] make Evaluable::eval's environment a mutable ref; --- ergotree-interpreter/src/eval.rs | 14 +++++++++----- ergotree-interpreter/src/eval/and.rs | 2 +- ergotree-interpreter/src/eval/apply.rs | 7 +++---- ergotree-interpreter/src/eval/atleast.rs | 2 +- ergotree-interpreter/src/eval/bin_op.rs | 2 +- ergotree-interpreter/src/eval/bit_inversion.rs | 2 +- ergotree-interpreter/src/eval/block.rs | 9 ++++----- ergotree-interpreter/src/eval/bool_to_sigma.rs | 2 +- .../src/eval/byte_array_to_bigint.rs | 2 +- .../src/eval/byte_array_to_long.rs | 2 +- ergotree-interpreter/src/eval/calc_blake2b256.rs | 2 +- ergotree-interpreter/src/eval/calc_sha256.rs | 2 +- ergotree-interpreter/src/eval/coll_append.rs | 2 +- ergotree-interpreter/src/eval/coll_by_index.rs | 2 +- ergotree-interpreter/src/eval/coll_exists.rs | 6 +++--- ergotree-interpreter/src/eval/coll_filter.rs | 6 +++--- ergotree-interpreter/src/eval/coll_fold.rs | 6 +++--- ergotree-interpreter/src/eval/coll_forall.rs | 6 +++--- ergotree-interpreter/src/eval/coll_map.rs | 6 +++--- ergotree-interpreter/src/eval/coll_size.rs | 2 +- ergotree-interpreter/src/eval/coll_slice.rs | 2 +- ergotree-interpreter/src/eval/collection.rs | 2 +- ergotree-interpreter/src/eval/create_avl_tree.rs | 2 +- .../src/eval/create_prove_dh_tuple.rs | 2 +- ergotree-interpreter/src/eval/create_provedlog.rs | 2 +- ergotree-interpreter/src/eval/decode_point.rs | 2 +- .../src/eval/deserialize_context.rs | 2 +- .../src/eval/deserialize_register.rs | 4 ++-- ergotree-interpreter/src/eval/downcast.rs | 2 +- ergotree-interpreter/src/eval/exponentiate.rs | 2 +- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-interpreter/src/eval/extract_amount.rs | 2 +- ergotree-interpreter/src/eval/extract_bytes.rs | 2 +- .../src/eval/extract_bytes_with_no_ref.rs | 2 +- .../src/eval/extract_creation_info.rs | 2 +- ergotree-interpreter/src/eval/extract_id.rs | 2 +- ergotree-interpreter/src/eval/extract_reg_as.rs | 2 +- .../src/eval/extract_script_bytes.rs | 2 +- ergotree-interpreter/src/eval/func_value.rs | 2 +- ergotree-interpreter/src/eval/get_var.rs | 2 +- ergotree-interpreter/src/eval/global_vars.rs | 2 +- ergotree-interpreter/src/eval/if_op.rs | 2 +- ergotree-interpreter/src/eval/logical_not.rs | 2 +- .../src/eval/long_to_byte_array.rs | 2 +- ergotree-interpreter/src/eval/method_call.rs | 2 +- ergotree-interpreter/src/eval/multiply_group.rs | 2 +- ergotree-interpreter/src/eval/negation.rs | 2 +- ergotree-interpreter/src/eval/option_get.rs | 2 +- .../src/eval/option_get_or_else.rs | 2 +- ergotree-interpreter/src/eval/option_is_defined.rs | 2 +- ergotree-interpreter/src/eval/or.rs | 2 +- ergotree-interpreter/src/eval/property_call.rs | 2 +- ergotree-interpreter/src/eval/scoll.rs | 4 ++-- ergotree-interpreter/src/eval/select_field.rs | 2 +- ergotree-interpreter/src/eval/sigma_and.rs | 2 +- ergotree-interpreter/src/eval/sigma_or.rs | 2 +- ergotree-interpreter/src/eval/sigma_prop_bytes.rs | 2 +- ergotree-interpreter/src/eval/soption.rs | 8 ++++---- ergotree-interpreter/src/eval/subst_const.rs | 2 +- ergotree-interpreter/src/eval/tree_lookup.rs | 2 +- ergotree-interpreter/src/eval/tuple.rs | 2 +- ergotree-interpreter/src/eval/upcast.rs | 2 +- ergotree-interpreter/src/eval/val_use.rs | 2 +- ergotree-interpreter/src/eval/xor.rs | 2 +- ergotree-interpreter/src/eval/xor_of.rs | 2 +- ergotree-interpreter/src/sigma_protocol/prover.rs | 6 ++++-- .../src/sigma_protocol/verifier.rs | 3 ++- 67 files changed, 99 insertions(+), 94 deletions(-) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index aefeda105..f201a74f9 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -164,12 +164,13 @@ pub struct ReductionResult { pub sigma_prop: SigmaBoolean, /// estimated cost of expression evaluation pub cost: u64, + // pub env: Env, } /// Evaluate the given expression by reducing it to SigmaBoolean value. pub fn reduce_to_crypto( expr: &Expr, - env: &Env, + env: &mut Env, ctx: Rc, ) -> Result { let cost_accum = CostAccumulator::new(0, None); @@ -214,10 +215,11 @@ impl EvalContext { /// Should be implemented by every node that can be evaluated. pub(crate) trait Evaluable { /// Evaluation routine to be implement by each node - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result; + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result; } -type EvalFn = fn(env: &Env, ctx: &mut EvalContext, Value, Vec) -> Result; +type EvalFn = + fn(env: &mut Env, ctx: &mut EvalContext, Value, Vec) -> Result; fn smethod_eval_fn(method: &SMethod) -> Result { use ergotree_ir::types::*; @@ -387,7 +389,8 @@ pub(crate) mod tests { pub fn eval_out>(expr: &Expr, ctx: Rc) -> T { let cost_accum = CostAccumulator::new(0, None); let mut ectx = EvalContext::new(ctx, cost_accum); - expr.eval(&Env::empty(), &mut ectx) + let mut env = Env::empty(); + expr.eval(&mut env, &mut ectx) .unwrap() .try_extract_into::() .unwrap() @@ -399,7 +402,8 @@ pub(crate) mod tests { ) -> Result { let cost_accum = CostAccumulator::new(0, None); let mut ectx = EvalContext::new(ctx, cost_accum); - expr.eval(&Env::empty(), &mut ectx) + let mut env = Env::empty(); + expr.eval(&mut env, &mut ectx) .and_then(|v| v.try_extract_into::().map_err(EvalError::TryExtractFrom)) } diff --git a/ergotree-interpreter/src/eval/and.rs b/ergotree-interpreter/src/eval/and.rs index 668520bb5..882227600 100644 --- a/ergotree-interpreter/src/eval/and.rs +++ b/ergotree-interpreter/src/eval/and.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for And { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let input_v_bools = input_v.try_extract_into::>()?; Ok(input_v_bools.iter().all(|b| *b).into()) diff --git a/ergotree-interpreter/src/eval/apply.rs b/ergotree-interpreter/src/eval/apply.rs index ceefbe8ea..073e0f1fd 100644 --- a/ergotree-interpreter/src/eval/apply.rs +++ b/ergotree-interpreter/src/eval/apply.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Apply { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let func_v = self.func.eval(env, ctx)?; let args_v_res: Result, EvalError> = self.args.iter().map(|arg| arg.eval(env, ctx)).collect(); @@ -16,11 +16,10 @@ impl Evaluable for Apply { match func_v { Value::Lambda(fv) => { let arg_ids: Vec = fv.args.iter().map(|a| a.idx).collect(); - let mut cur_env = env.clone(); arg_ids.iter().zip(args_v).for_each(|(idx, arg_v)| { - cur_env.insert(*idx, arg_v); + env.insert(*idx, arg_v); }); - fv.body.eval(&cur_env, ctx) + fv.body.eval(env, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected func_v to be Value::FuncValue got: {0:?}", diff --git a/ergotree-interpreter/src/eval/atleast.rs b/ergotree-interpreter/src/eval/atleast.rs index e15f31442..93b56ff36 100644 --- a/ergotree-interpreter/src/eval/atleast.rs +++ b/ergotree-interpreter/src/eval/atleast.rs @@ -14,7 +14,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Atleast { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let bound_v = self.bound.eval(env, ctx)?; let input_v = self.input.eval(env, ctx)?; diff --git a/ergotree-interpreter/src/eval/bin_op.rs b/ergotree-interpreter/src/eval/bin_op.rs index 146c0387d..2a47f9ceb 100644 --- a/ergotree-interpreter/src/eval/bin_op.rs +++ b/ergotree-interpreter/src/eval/bin_op.rs @@ -171,7 +171,7 @@ where } impl Evaluable for BinOp { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { ctx.cost_accum.add(Costs::DEFAULT.eq_const_size)?; let lv = self.left.eval(env, ctx)?; // using closure to keep right value from evaluation (for lazy AND, OR, XOR) diff --git a/ergotree-interpreter/src/eval/bit_inversion.rs b/ergotree-interpreter/src/eval/bit_inversion.rs index 61bd51653..18541f474 100644 --- a/ergotree-interpreter/src/eval/bit_inversion.rs +++ b/ergotree-interpreter/src/eval/bit_inversion.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for BitInversion { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::Byte(v) => Ok(Value::Byte(!v)), diff --git a/ergotree-interpreter/src/eval/block.rs b/ergotree-interpreter/src/eval/block.rs index 2562d66d3..fc73b5be2 100644 --- a/ergotree-interpreter/src/eval/block.rs +++ b/ergotree-interpreter/src/eval/block.rs @@ -9,14 +9,13 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for BlockValue { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { - let mut cur_env = env.clone(); + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { for i in &self.items { let val_def = i.clone().try_extract_into::()?; - let v: Value = val_def.rhs.eval(&cur_env, ctx)?; - cur_env.insert(val_def.id, v); + let v: Value = val_def.rhs.eval(env, ctx)?; + env.insert(val_def.id, v); } - self.result.eval(&cur_env, ctx) + self.result.eval(env, ctx) } } diff --git a/ergotree-interpreter/src/eval/bool_to_sigma.rs b/ergotree-interpreter/src/eval/bool_to_sigma.rs index 591ce4760..3f249c052 100644 --- a/ergotree-interpreter/src/eval/bool_to_sigma.rs +++ b/ergotree-interpreter/src/eval/bool_to_sigma.rs @@ -10,7 +10,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for BoolToSigmaProp { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let input_v_bool = input_v.try_extract_into::()?; Ok((SigmaProp::new(SigmaBoolean::TrivialProp(input_v_bool))).into()) diff --git a/ergotree-interpreter/src/eval/byte_array_to_bigint.rs b/ergotree-interpreter/src/eval/byte_array_to_bigint.rs index a31d3a751..695607cc4 100644 --- a/ergotree-interpreter/src/eval/byte_array_to_bigint.rs +++ b/ergotree-interpreter/src/eval/byte_array_to_bigint.rs @@ -12,7 +12,7 @@ use crate::eval::EvalError::UnexpectedValue; use crate::eval::Evaluable; impl Evaluable for ByteArrayToBigInt { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input = self.input.eval(env, ctx)?.try_extract_into::>()?; if input.is_empty() { return Err(UnexpectedValue( diff --git a/ergotree-interpreter/src/eval/byte_array_to_long.rs b/ergotree-interpreter/src/eval/byte_array_to_long.rs index e97ca35ed..bd2c3b8c0 100644 --- a/ergotree-interpreter/src/eval/byte_array_to_long.rs +++ b/ergotree-interpreter/src/eval/byte_array_to_long.rs @@ -9,7 +9,7 @@ use crate::eval::Evaluable; use ergotree_ir::mir::constant::TryExtractInto; impl Evaluable for ByteArrayToLong { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input = self.input.eval(env, ctx)?.try_extract_into::>()?; if input.len() < 8 { return Err(UnexpectedValue( diff --git a/ergotree-interpreter/src/eval/calc_blake2b256.rs b/ergotree-interpreter/src/eval/calc_blake2b256.rs index 3d5485ace..4c97ef5c6 100644 --- a/ergotree-interpreter/src/eval/calc_blake2b256.rs +++ b/ergotree-interpreter/src/eval/calc_blake2b256.rs @@ -11,7 +11,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CalcBlake2b256 { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v.clone() { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(coll_byte))) => { diff --git a/ergotree-interpreter/src/eval/calc_sha256.rs b/ergotree-interpreter/src/eval/calc_sha256.rs index 3d01d786e..3cefa834c 100644 --- a/ergotree-interpreter/src/eval/calc_sha256.rs +++ b/ergotree-interpreter/src/eval/calc_sha256.rs @@ -11,7 +11,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CalcSha256 { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v.clone() { Value::Coll(CollKind::NativeColl(NativeColl::CollByte(coll_byte))) => { diff --git a/ergotree-interpreter/src/eval/coll_append.rs b/ergotree-interpreter/src/eval/coll_append.rs index 7b2d58144..7d02792fe 100644 --- a/ergotree-interpreter/src/eval/coll_append.rs +++ b/ergotree-interpreter/src/eval/coll_append.rs @@ -35,7 +35,7 @@ fn extract_elem_tpe(inp: &Value) -> Result { } impl Evaluable for Append { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let col2_v = self.col_2.eval(env, ctx)?; let input_elem_tpe = extract_elem_tpe(&input_v)?; diff --git a/ergotree-interpreter/src/eval/coll_by_index.rs b/ergotree-interpreter/src/eval/coll_by_index.rs index a79683b59..e6f47ec53 100644 --- a/ergotree-interpreter/src/eval/coll_by_index.rs +++ b/ergotree-interpreter/src/eval/coll_by_index.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ByIndex { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let index_v = self.index.eval(env, ctx)?; let normalized_input_vals: Vec = match input_v { diff --git a/ergotree-interpreter/src/eval/coll_exists.rs b/ergotree-interpreter/src/eval/coll_exists.rs index 4819d0b5a..2a97500c2 100644 --- a/ergotree-interpreter/src/eval/coll_exists.rs +++ b/ergotree-interpreter/src/eval/coll_exists.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Exists { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); @@ -19,8 +19,8 @@ impl Evaluable for Exists { "Exists: evaluated condition has empty arguments list".to_string(), ) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - func_value.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + func_value.body.eval(env, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected Exists::condition to be Value::FuncValue got: {0:?}", diff --git a/ergotree-interpreter/src/eval/coll_filter.rs b/ergotree-interpreter/src/eval/coll_filter.rs index 28fc94d82..951adaf63 100644 --- a/ergotree-interpreter/src/eval/coll_filter.rs +++ b/ergotree-interpreter/src/eval/coll_filter.rs @@ -9,7 +9,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Filter { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); @@ -20,8 +20,8 @@ impl Evaluable for Filter { "Filter: evaluated condition has empty arguments list".to_string(), ) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - func_value.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + func_value.body.eval(env, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected Filter::condition to be Value::FuncValue got: {0:?}", diff --git a/ergotree-interpreter/src/eval/coll_fold.rs b/ergotree-interpreter/src/eval/coll_fold.rs index 6b3e10fc1..a32ff92c2 100644 --- a/ergotree-interpreter/src/eval/coll_fold.rs +++ b/ergotree-interpreter/src/eval/coll_fold.rs @@ -9,7 +9,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Fold { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let zero_v = self.zero.eval(env, ctx)?; let fold_op_v = self.fold_op.eval(env, ctx)?; @@ -20,8 +20,8 @@ impl Evaluable for Fold { .args .first() .ok_or_else(|| EvalError::NotFound("empty argument for fold op".to_string()))?; - let env1 = env.clone().extend(func_arg.idx, arg); - func_value.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + func_value.body.eval(env, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected fold_op to be Value::FuncValue got: {0:?}", diff --git a/ergotree-interpreter/src/eval/coll_forall.rs b/ergotree-interpreter/src/eval/coll_forall.rs index 186ec5f45..0dec1520a 100644 --- a/ergotree-interpreter/src/eval/coll_forall.rs +++ b/ergotree-interpreter/src/eval/coll_forall.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ForAll { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); @@ -19,8 +19,8 @@ impl Evaluable for ForAll { "ForAll: evaluated condition has empty arguments list".to_string(), ) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - func_value.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + func_value.body.eval(env, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected ForAll::condition to be Value::FuncValue got: {0:?}", diff --git a/ergotree-interpreter/src/eval/coll_map.rs b/ergotree-interpreter/src/eval/coll_map.rs index 9b76ada8b..6745d08f3 100644 --- a/ergotree-interpreter/src/eval/coll_map.rs +++ b/ergotree-interpreter/src/eval/coll_map.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Map { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let mapper_v = self.mapper.eval(env, ctx)?; let input_v_clone = input_v.clone(); @@ -19,8 +19,8 @@ impl Evaluable for Map { "Map: evaluated mapper has empty arguments list".to_string(), ) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - func_value.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + func_value.body.eval(env, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected mapper to be Value::FuncValue got: {0:?}", diff --git a/ergotree-interpreter/src/eval/coll_size.rs b/ergotree-interpreter/src/eval/coll_size.rs index 87db1e37c..2f8cb4614 100644 --- a/ergotree-interpreter/src/eval/coll_size.rs +++ b/ergotree-interpreter/src/eval/coll_size.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SizeOf { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let normalized_input_vals: Vec = match input_v { Value::Coll(coll) => Ok(coll.as_vec()), diff --git a/ergotree-interpreter/src/eval/coll_slice.rs b/ergotree-interpreter/src/eval/coll_slice.rs index feef572f0..c39de608a 100644 --- a/ergotree-interpreter/src/eval/coll_slice.rs +++ b/ergotree-interpreter/src/eval/coll_slice.rs @@ -9,7 +9,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Slice { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let from_v = self.from.eval(env, ctx)?; let until_v = self.until.eval(env, ctx)?; diff --git a/ergotree-interpreter/src/eval/collection.rs b/ergotree-interpreter/src/eval/collection.rs index 185acad0d..e497e22f6 100644 --- a/ergotree-interpreter/src/eval/collection.rs +++ b/ergotree-interpreter/src/eval/collection.rs @@ -12,7 +12,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Collection { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { Ok(match self { Collection::BoolConstants(bools) => bools.clone().into(), Collection::Exprs { elem_tpe, items } => { diff --git a/ergotree-interpreter/src/eval/create_avl_tree.rs b/ergotree-interpreter/src/eval/create_avl_tree.rs index e493d08a0..e9a3dd4c5 100644 --- a/ergotree-interpreter/src/eval/create_avl_tree.rs +++ b/ergotree-interpreter/src/eval/create_avl_tree.rs @@ -11,7 +11,7 @@ use sigma_util::AsVecU8; use std::convert::TryFrom; impl Evaluable for CreateAvlTree { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let flags_v = self.flags.eval(env, ctx)?.try_extract_into::()? as u8; let digest_v = self.digest.eval(env, ctx)?.try_extract_into::>()?; let key_length = self.key_length.eval(env, ctx)?.try_extract_into::()? as u32; diff --git a/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs b/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs index d06f9c604..e58311b16 100644 --- a/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs +++ b/ergotree-interpreter/src/eval/create_prove_dh_tuple.rs @@ -10,7 +10,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CreateProveDhTuple { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let g = self.g.eval(env, ctx)?.try_extract_into::()?; let h = self.h.eval(env, ctx)?.try_extract_into::()?; let u = self.u.eval(env, ctx)?.try_extract_into::()?; diff --git a/ergotree-interpreter/src/eval/create_provedlog.rs b/ergotree-interpreter/src/eval/create_provedlog.rs index b672cc79e..dc0036a1b 100644 --- a/ergotree-interpreter/src/eval/create_provedlog.rs +++ b/ergotree-interpreter/src/eval/create_provedlog.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for CreateProveDlog { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let value_v = self.input.eval(env, ctx)?; match value_v { Value::GroupElement(ecpoint) => { diff --git a/ergotree-interpreter/src/eval/decode_point.rs b/ergotree-interpreter/src/eval/decode_point.rs index 8ef37704b..61de550ed 100644 --- a/ergotree-interpreter/src/eval/decode_point.rs +++ b/ergotree-interpreter/src/eval/decode_point.rs @@ -11,7 +11,7 @@ use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::serialization::SigmaSerializable; impl Evaluable for DecodePoint { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let point_bytes = self.input.eval(env, ctx)?.try_extract_into::>()?; let point: EcPoint = SigmaSerializable::sigma_parse_bytes(&point_bytes).map_err(|_| { Misc(String::from( diff --git a/ergotree-interpreter/src/eval/deserialize_context.rs b/ergotree-interpreter/src/eval/deserialize_context.rs index 4fa22e2fe..cbb88fcd2 100644 --- a/ergotree-interpreter/src/eval/deserialize_context.rs +++ b/ergotree-interpreter/src/eval/deserialize_context.rs @@ -11,7 +11,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for DeserializeContext { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { match ctx.ctx.extension.values.get(&self.id) { Some(c) => { if c.tpe != SType::SColl(SType::SByte.into()) { diff --git a/ergotree-interpreter/src/eval/deserialize_register.rs b/ergotree-interpreter/src/eval/deserialize_register.rs index 92d4dfad0..5204316c9 100644 --- a/ergotree-interpreter/src/eval/deserialize_register.rs +++ b/ergotree-interpreter/src/eval/deserialize_register.rs @@ -13,7 +13,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for DeserializeRegister { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { match ctx .ctx .self_box @@ -60,7 +60,7 @@ impl Evaluable for DeserializeRegister { fn eval_default( deserialize_reg_tpe: &SType, default_expr: &Expr, - env: &Env, + env: &mut Env, ctx: &mut EvalContext, ) -> Result { if &default_expr.tpe() != deserialize_reg_tpe { diff --git a/ergotree-interpreter/src/eval/downcast.rs b/ergotree-interpreter/src/eval/downcast.rs index 639cbd0ab..003c5f1b4 100644 --- a/ergotree-interpreter/src/eval/downcast.rs +++ b/ergotree-interpreter/src/eval/downcast.rs @@ -104,7 +104,7 @@ fn downcast_to_byte(in_v: Value) -> Result { } impl Evaluable for Downcast { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match self.tpe { SType::SBigInt => downcast_to_bigint(input_v), diff --git a/ergotree-interpreter/src/eval/exponentiate.rs b/ergotree-interpreter/src/eval/exponentiate.rs index 5326d8a9e..dc00bd0f7 100644 --- a/ergotree-interpreter/src/eval/exponentiate.rs +++ b/ergotree-interpreter/src/eval/exponentiate.rs @@ -9,7 +9,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Exponentiate { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let left_v = self.left.eval(env, ctx)?; let right_v = self.right.eval(env, ctx)?; diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index e36aff9a0..3439ff78c 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -7,7 +7,7 @@ use super::EvalError; use super::Evaluable; impl Evaluable for Expr { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { ctx.cost_accum.add_cost_of(self)?; match self { Expr::Const(c) => Ok(Value::from(c.v.clone())), diff --git a/ergotree-interpreter/src/eval/extract_amount.rs b/ergotree-interpreter/src/eval/extract_amount.rs index 196ad030e..25c4e3cce 100644 --- a/ergotree-interpreter/src/eval/extract_amount.rs +++ b/ergotree-interpreter/src/eval/extract_amount.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractAmount { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(Value::Long(b.value.as_i64())), diff --git a/ergotree-interpreter/src/eval/extract_bytes.rs b/ergotree-interpreter/src/eval/extract_bytes.rs index 98af3d964..060fe203e 100644 --- a/ergotree-interpreter/src/eval/extract_bytes.rs +++ b/ergotree-interpreter/src/eval/extract_bytes.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractBytes { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.sigma_serialize_bytes()?.into()), diff --git a/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs b/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs index bd30d2723..f97e8fd1e 100644 --- a/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs +++ b/ergotree-interpreter/src/eval/extract_bytes_with_no_ref.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractBytesWithNoRef { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.bytes_without_ref()?.into()), diff --git a/ergotree-interpreter/src/eval/extract_creation_info.rs b/ergotree-interpreter/src/eval/extract_creation_info.rs index bda52b36c..0cebb3376 100644 --- a/ergotree-interpreter/src/eval/extract_creation_info.rs +++ b/ergotree-interpreter/src/eval/extract_creation_info.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractCreationInfo { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.creation_info().into()), diff --git a/ergotree-interpreter/src/eval/extract_id.rs b/ergotree-interpreter/src/eval/extract_id.rs index 83571158a..ce7d9c18d 100644 --- a/ergotree-interpreter/src/eval/extract_id.rs +++ b/ergotree-interpreter/src/eval/extract_id.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractId { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => { diff --git a/ergotree-interpreter/src/eval/extract_reg_as.rs b/ergotree-interpreter/src/eval/extract_reg_as.rs index a9bd6efa7..6940a0b4d 100644 --- a/ergotree-interpreter/src/eval/extract_reg_as.rs +++ b/ergotree-interpreter/src/eval/extract_reg_as.rs @@ -12,7 +12,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractRegisterAs { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let ir_box = self .input .eval(env, ctx)? diff --git a/ergotree-interpreter/src/eval/extract_script_bytes.rs b/ergotree-interpreter/src/eval/extract_script_bytes.rs index 745936e4f..71075ced4 100644 --- a/ergotree-interpreter/src/eval/extract_script_bytes.rs +++ b/ergotree-interpreter/src/eval/extract_script_bytes.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ExtractScriptBytes { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::CBox(b) => Ok(b.script_bytes()?.into()), diff --git a/ergotree-interpreter/src/eval/func_value.rs b/ergotree-interpreter/src/eval/func_value.rs index f342bb1e6..1cf0d944a 100644 --- a/ergotree-interpreter/src/eval/func_value.rs +++ b/ergotree-interpreter/src/eval/func_value.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for FuncValue { - fn eval(&self, _env: &Env, _ctx: &mut EvalContext) -> Result { + fn eval(&self, _env: &mut Env, _ctx: &mut EvalContext) -> Result { Ok(Value::Lambda(Lambda { args: self.args().to_vec(), body: self.body().clone().into(), diff --git a/ergotree-interpreter/src/eval/get_var.rs b/ergotree-interpreter/src/eval/get_var.rs index 276742a51..07bbbfb7c 100644 --- a/ergotree-interpreter/src/eval/get_var.rs +++ b/ergotree-interpreter/src/eval/get_var.rs @@ -9,7 +9,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for GetVar { - fn eval(&self, _env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, _env: &mut Env, ctx: &mut EvalContext) -> Result { match ctx.ctx.extension.values.get(&self.var_id) { None => Ok(Value::Opt(None.into())), Some(v) if v.tpe == self.var_tpe => Ok((Some(v.v.clone())).into()), diff --git a/ergotree-interpreter/src/eval/global_vars.rs b/ergotree-interpreter/src/eval/global_vars.rs index 9f1371ee6..148c6e7de 100644 --- a/ergotree-interpreter/src/eval/global_vars.rs +++ b/ergotree-interpreter/src/eval/global_vars.rs @@ -8,7 +8,7 @@ use super::EvalError; use super::Evaluable; impl Evaluable for GlobalVars { - fn eval(&self, _env: &Env, ectx: &mut EvalContext) -> Result { + fn eval(&self, _env: &mut Env, ectx: &mut EvalContext) -> Result { match self { GlobalVars::Height => Ok((ectx.ctx.height as i32).into()), GlobalVars::SelfBox => Ok(ectx.ctx.self_box.clone().into()), diff --git a/ergotree-interpreter/src/eval/if_op.rs b/ergotree-interpreter/src/eval/if_op.rs index 0795c7674..fce7a6ede 100644 --- a/ergotree-interpreter/src/eval/if_op.rs +++ b/ergotree-interpreter/src/eval/if_op.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for If { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let condition_v = self.condition.eval(env, ctx)?; if condition_v.try_extract_into::()? { self.true_branch.eval(env, ctx) diff --git a/ergotree-interpreter/src/eval/logical_not.rs b/ergotree-interpreter/src/eval/logical_not.rs index 9d9829b13..2e2c8ec62 100644 --- a/ergotree-interpreter/src/eval/logical_not.rs +++ b/ergotree-interpreter/src/eval/logical_not.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for LogicalNot { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let input_v_bool = input_v.try_extract_into::()?; Ok((!input_v_bool).into()) diff --git a/ergotree-interpreter/src/eval/long_to_byte_array.rs b/ergotree-interpreter/src/eval/long_to_byte_array.rs index cba7a4a98..745e0ff3e 100644 --- a/ergotree-interpreter/src/eval/long_to_byte_array.rs +++ b/ergotree-interpreter/src/eval/long_to_byte_array.rs @@ -8,7 +8,7 @@ use crate::eval::Evaluable; use ergotree_ir::mir::constant::TryExtractInto; impl Evaluable for LongToByteArray { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let mut val = self.input.eval(env, ctx)?.try_extract_into::()?; let mut buf = vec![42_i8; 8]; for i in (0..8).rev() { diff --git a/ergotree-interpreter/src/eval/method_call.rs b/ergotree-interpreter/src/eval/method_call.rs index 5791db03f..fe6ac8174 100644 --- a/ergotree-interpreter/src/eval/method_call.rs +++ b/ergotree-interpreter/src/eval/method_call.rs @@ -8,7 +8,7 @@ use super::EvalError; use super::Evaluable; impl Evaluable for MethodCall { - fn eval(&self, env: &Env, ectx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ectx: &mut EvalContext) -> Result { let ov = self.obj.eval(env, ectx)?; let argsv: Result, EvalError> = self.args.iter().map(|arg| arg.eval(env, ectx)).collect(); diff --git a/ergotree-interpreter/src/eval/multiply_group.rs b/ergotree-interpreter/src/eval/multiply_group.rs index de6d8a732..aa1973f52 100644 --- a/ergotree-interpreter/src/eval/multiply_group.rs +++ b/ergotree-interpreter/src/eval/multiply_group.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for MultiplyGroup { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let left_v = self.left.eval(env, ctx)?; let right_v = self.right.eval(env, ctx)?; diff --git a/ergotree-interpreter/src/eval/negation.rs b/ergotree-interpreter/src/eval/negation.rs index dc58a609b..5a6b15129 100644 --- a/ergotree-interpreter/src/eval/negation.rs +++ b/ergotree-interpreter/src/eval/negation.rs @@ -8,7 +8,7 @@ use crate::eval::Evaluable; use num_traits::CheckedNeg; impl Evaluable for Negation { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; fn overflow_err(v: &T) -> EvalError { diff --git a/ergotree-interpreter/src/eval/option_get.rs b/ergotree-interpreter/src/eval/option_get.rs index d844887bf..bcbace334 100644 --- a/ergotree-interpreter/src/eval/option_get.rs +++ b/ergotree-interpreter/src/eval/option_get.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for OptionGet { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let v = self.input.eval(env, ctx)?; match v { Value::Opt(opt_v) => { diff --git a/ergotree-interpreter/src/eval/option_get_or_else.rs b/ergotree-interpreter/src/eval/option_get_or_else.rs index c29844eff..5e307518a 100644 --- a/ergotree-interpreter/src/eval/option_get_or_else.rs +++ b/ergotree-interpreter/src/eval/option_get_or_else.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for OptionGetOrElse { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let v = self.input.eval(env, ctx)?; let default_v = self.default.eval(env, ctx)?; match v { diff --git a/ergotree-interpreter/src/eval/option_is_defined.rs b/ergotree-interpreter/src/eval/option_is_defined.rs index a85bc6969..814667ab9 100644 --- a/ergotree-interpreter/src/eval/option_is_defined.rs +++ b/ergotree-interpreter/src/eval/option_is_defined.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for OptionIsDefined { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let v = self.input.eval(env, ctx)?; match v { Value::Opt(opt_v) => Ok(opt_v.is_some().into()), diff --git a/ergotree-interpreter/src/eval/or.rs b/ergotree-interpreter/src/eval/or.rs index 8e212e06d..561fb4dc7 100644 --- a/ergotree-interpreter/src/eval/or.rs +++ b/ergotree-interpreter/src/eval/or.rs @@ -8,7 +8,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Or { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let input_v_bools = input_v.try_extract_into::>()?; Ok(input_v_bools.iter().any(|b| *b).into()) diff --git a/ergotree-interpreter/src/eval/property_call.rs b/ergotree-interpreter/src/eval/property_call.rs index c36479b25..79996caa3 100644 --- a/ergotree-interpreter/src/eval/property_call.rs +++ b/ergotree-interpreter/src/eval/property_call.rs @@ -8,7 +8,7 @@ use super::EvalError; use super::Evaluable; impl Evaluable for PropertyCall { - fn eval(&self, env: &Env, ectx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ectx: &mut EvalContext) -> Result { let ov = self.obj.eval(env, ectx)?; smethod_eval_fn(&self.method)?(env, ectx, ov, vec![]) } diff --git a/ergotree-interpreter/src/eval/scoll.rs b/ergotree-interpreter/src/eval/scoll.rs index 8256e5657..d4f5eea27 100644 --- a/ergotree-interpreter/src/eval/scoll.rs +++ b/ergotree-interpreter/src/eval/scoll.rs @@ -75,8 +75,8 @@ pub(crate) static FLATMAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { let func_arg = lambda.args.first().ok_or_else(|| { EvalError::NotFound("flatmap: lambda has empty arguments list".to_string()) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - lambda.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + lambda.body.eval(env, ctx) }; let mapper_input_tpe = lambda .args diff --git a/ergotree-interpreter/src/eval/select_field.rs b/ergotree-interpreter/src/eval/select_field.rs index c5aea0a92..9bb4ebbf9 100644 --- a/ergotree-interpreter/src/eval/select_field.rs +++ b/ergotree-interpreter/src/eval/select_field.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SelectField { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::Tup(items) => items diff --git a/ergotree-interpreter/src/eval/sigma_and.rs b/ergotree-interpreter/src/eval/sigma_and.rs index 7912d6c7b..de9437520 100644 --- a/ergotree-interpreter/src/eval/sigma_and.rs +++ b/ergotree-interpreter/src/eval/sigma_and.rs @@ -10,7 +10,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SigmaAnd { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let items_v_res = self.items.try_mapped_ref(|it| it.eval(env, ctx)); let items_sigmabool = items_v_res? .try_mapped(|it| it.try_extract_into::())? diff --git a/ergotree-interpreter/src/eval/sigma_or.rs b/ergotree-interpreter/src/eval/sigma_or.rs index 1ef93782e..b2324e06a 100644 --- a/ergotree-interpreter/src/eval/sigma_or.rs +++ b/ergotree-interpreter/src/eval/sigma_or.rs @@ -10,7 +10,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SigmaOr { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let items_v_res = self.items.try_mapped_ref(|it| it.eval(env, ctx)); let items_sigmabool = items_v_res? .try_mapped(|it| it.try_extract_into::())? diff --git a/ergotree-interpreter/src/eval/sigma_prop_bytes.rs b/ergotree-interpreter/src/eval/sigma_prop_bytes.rs index 09a395b07..11cbde0ed 100644 --- a/ergotree-interpreter/src/eval/sigma_prop_bytes.rs +++ b/ergotree-interpreter/src/eval/sigma_prop_bytes.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for SigmaPropBytes { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match input_v { Value::SigmaProp(sigma_prop) => Ok(sigma_prop.prop_bytes()?.into()), diff --git a/ergotree-interpreter/src/eval/soption.rs b/ergotree-interpreter/src/eval/soption.rs index e2c4932fb..f981f1444 100644 --- a/ergotree-interpreter/src/eval/soption.rs +++ b/ergotree-interpreter/src/eval/soption.rs @@ -23,8 +23,8 @@ pub(crate) static MAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { let func_arg = lambda.args.first().ok_or_else(|| { EvalError::NotFound("map: lambda has empty arguments list".to_string()) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - lambda.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + lambda.body.eval(env, ctx) }; let normalized_input_val: Option = match input_v { Value::Opt(opt) => Ok(*opt), @@ -58,8 +58,8 @@ pub(crate) static FILTER_EVAL_FN: EvalFn = |env, ctx, obj, args| { let func_arg = lambda.args.first().ok_or_else(|| { EvalError::NotFound("filter: lambda has empty arguments list".to_string()) })?; - let env1 = env.clone().extend(func_arg.idx, arg); - lambda.body.eval(&env1, ctx) + env.insert(func_arg.idx, arg); + lambda.body.eval(env, ctx) }; let normalized_input_val: Option = match input_v { Value::Opt(opt) => Ok(*opt), diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs index f99e52481..97825336c 100644 --- a/ergotree-interpreter/src/eval/subst_const.rs +++ b/ergotree-interpreter/src/eval/subst_const.rs @@ -15,7 +15,7 @@ use sigma_util::AsVecU8; use std::convert::TryFrom; impl Evaluable for SubstConstants { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let script_bytes_v = self.script_bytes.eval(env, ctx)?; let positions_v = self.positions.eval(env, ctx)?; let new_values_v = self.new_values.eval(env, ctx)?; diff --git a/ergotree-interpreter/src/eval/tree_lookup.rs b/ergotree-interpreter/src/eval/tree_lookup.rs index 379dfefb9..b4a8e7ae3 100644 --- a/ergotree-interpreter/src/eval/tree_lookup.rs +++ b/ergotree-interpreter/src/eval/tree_lookup.rs @@ -14,7 +14,7 @@ use scorex_crypto_avltree::operation::Operation; use sigma_util::AsVecU8; impl Evaluable for TreeLookup { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let normalized_tree_val = self .tree .eval(env, ctx)? diff --git a/ergotree-interpreter/src/eval/tuple.rs b/ergotree-interpreter/src/eval/tuple.rs index 0a1ea5261..7ed505b22 100644 --- a/ergotree-interpreter/src/eval/tuple.rs +++ b/ergotree-interpreter/src/eval/tuple.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Tuple { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let items_v = self.items.try_mapped_ref(|i| i.eval(env, ctx)); Ok(Value::Tup(items_v?)) } diff --git a/ergotree-interpreter/src/eval/upcast.rs b/ergotree-interpreter/src/eval/upcast.rs index 878e0a66f..647cdf1f1 100644 --- a/ergotree-interpreter/src/eval/upcast.rs +++ b/ergotree-interpreter/src/eval/upcast.rs @@ -69,7 +69,7 @@ fn upcast_to_byte(in_v: Value) -> Result { } impl Evaluable for Upcast { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; match self.tpe { SType::SBigInt => upcast_to_bigint(input_v), diff --git a/ergotree-interpreter/src/eval/val_use.rs b/ergotree-interpreter/src/eval/val_use.rs index fa647df5a..53ddfa9ae 100644 --- a/ergotree-interpreter/src/eval/val_use.rs +++ b/ergotree-interpreter/src/eval/val_use.rs @@ -7,7 +7,7 @@ use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for ValUse { - fn eval(&self, env: &Env, _ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, _ctx: &mut EvalContext) -> Result { env.get(self.val_id).cloned().ok_or_else(|| { EvalError::NotFound(format!("no value in env for id: {0:?}", self.val_id)) }) diff --git a/ergotree-interpreter/src/eval/xor.rs b/ergotree-interpreter/src/eval/xor.rs index 88a51ef84..254c3e208 100644 --- a/ergotree-interpreter/src/eval/xor.rs +++ b/ergotree-interpreter/src/eval/xor.rs @@ -14,7 +14,7 @@ fn helper_xor(mut x: Vec, y: Vec) -> Vec { } impl Evaluable for Xor { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let left_v = self.left.eval(env, ctx)?; let right_v = self.right.eval(env, ctx)?; diff --git a/ergotree-interpreter/src/eval/xor_of.rs b/ergotree-interpreter/src/eval/xor_of.rs index 028122074..8e7ca385c 100644 --- a/ergotree-interpreter/src/eval/xor_of.rs +++ b/ergotree-interpreter/src/eval/xor_of.rs @@ -8,7 +8,7 @@ use crate::eval::Evaluable; use ergotree_ir::mir::xor_of::XorOf; impl Evaluable for XorOf { - fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let input_v = self.input.eval(env, ctx)?; let input_v_bools = input_v.try_extract_into::>()?; Ok(input_v_bools.into_iter().fold(false, |a, b| a ^ b).into()) diff --git a/ergotree-interpreter/src/sigma_protocol/prover.rs b/ergotree-interpreter/src/sigma_protocol/prover.rs index 61a9b5324..8549baeac 100644 --- a/ergotree-interpreter/src/sigma_protocol/prover.rs +++ b/ergotree-interpreter/src/sigma_protocol/prover.rs @@ -132,7 +132,7 @@ pub trait Prover { /// The comments in this section are taken from the algorithm for the /// Sigma-protocol prover as described in the ErgoScript white-paper /// , Appendix A - /// + /// /// Generate proofs for the given message for ErgoTree reduced to Sigma boolean expression fn prove( &self, @@ -144,7 +144,9 @@ pub trait Prover { ) -> Result { let expr = tree.proposition()?; let ctx_ext = ctx.extension.clone(); - let reduction_result = reduce_to_crypto(&expr, env, ctx).map_err(ProverError::EvalError)?; + let mut env_mut = env.clone(); + let reduction_result = + reduce_to_crypto(&expr, &mut env_mut, ctx).map_err(ProverError::EvalError)?; self.generate_proof(reduction_result.sigma_prop, message, hints_bag) .map(|p| ProverResult { diff --git a/ergotree-interpreter/src/sigma_protocol/verifier.rs b/ergotree-interpreter/src/sigma_protocol/verifier.rs index 7219b9e68..8101cbbc9 100644 --- a/ergotree-interpreter/src/sigma_protocol/verifier.rs +++ b/ergotree-interpreter/src/sigma_protocol/verifier.rs @@ -66,7 +66,8 @@ pub trait Verifier { message: &[u8], ) -> Result { let expr = tree.proposition()?; - let cprop = reduce_to_crypto(&expr, env, ctx)?.sigma_prop; + let mut env_mut = env.clone(); + let cprop = reduce_to_crypto(&expr, &mut env_mut, ctx)?.sigma_prop; let res: bool = match cprop { SigmaBoolean::TrivialProp(b) => b, sb => { From 0e819e9bea2bc829c58f49cda03e31f6efab6717 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 18 Jul 2023 11:54:44 +0300 Subject: [PATCH 02/74] add EvalError::WrappedWithEnvError with evaluation env attached; --- ergo-lib/src/chain/transaction/reduced.rs | 7 ++++- ergotree-interpreter/src/contracts.rs | 26 +++++++++++-------- ergotree-interpreter/src/eval.rs | 22 +++++++++++++--- .../src/sigma_protocol/prover.rs | 5 +--- .../src/sigma_protocol/verifier.rs | 3 +-- ergotree-ir/src/mir/val_def.rs | 3 ++- 6 files changed, 44 insertions(+), 22 deletions(-) diff --git a/ergo-lib/src/chain/transaction/reduced.rs b/ergo-lib/src/chain/transaction/reduced.rs index 4e2c542b9..c3a19a98c 100644 --- a/ergo-lib/src/chain/transaction/reduced.rs +++ b/ergo-lib/src/chain/transaction/reduced.rs @@ -123,7 +123,11 @@ impl SigmaSerializable for ReducedTransaction { let cost = r.get_u64()?; let extension = input.spending_proof.extension; let reduced_input = ReducedInput { - reduction_result: ReductionResult { sigma_prop, cost }, + reduction_result: ReductionResult { + sigma_prop, + cost, + env: Env::empty(), + }, extension: extension.clone(), }; let unsigned_input = UnsignedInput { @@ -167,6 +171,7 @@ pub mod arbitrary { reduction_result: ReductionResult { sigma_prop: sb.clone(), cost: 0, + env: Env::empty(), }, extension: unsigned_input.extension, }), diff --git a/ergotree-interpreter/src/contracts.rs b/ergotree-interpreter/src/contracts.rs index a1c27154f..b3e47cc07 100644 --- a/ergotree-interpreter/src/contracts.rs +++ b/ergotree-interpreter/src/contracts.rs @@ -213,11 +213,9 @@ mod tests { let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); assert!(addr.script().unwrap().proposition().is_ok()); - let _script = addr.script().unwrap().proposition().unwrap(); + // let script = addr.script().unwrap().proposition().unwrap(); // dbg!(&script); - // let res: bool = eval_out_wo_ctx::(script.as_ref()) - // .try_into() - // .unwrap(); + // let res: bool = eval_out_wo_ctx::(&script).try_into().unwrap(); // assert!(!res); } @@ -227,12 +225,9 @@ mod tests { let p2s_addr_str = "cLPHJ3MHuKAHoCUwGhcEFw5sWJqvPwFyKxTRj1aUoMwgAz78Fg3zLXRhBup9Te1WLau1gZXNmXvUmeXGCd7QLeqB7ArrT3v5cg26piEtqymM6j2SkgYVCobgoAGKeTf6nMLxv1uVrLdjt1GnPxG1MuWj7Es7Dfumotbx9YEaxwqtTUC5SKsJc9LCpAmNWRAQbU6tVVEvmfwWivrGoZ3L5C4DMisxN3U"; let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); - let _script = addr.script().unwrap().proposition().unwrap(); - // dbg!(&script); - // let res: bool = eval_out_wo_ctx::(script.as_ref()) - // .try_into() - // .unwrap(); - // assert!(!res); + let _ = addr.script().unwrap().proposition().unwrap(); + // let ctx = Rc::new(force_any_val::()); + // let _ = reduce_to_crypto(&script, &Env::empty(), ctx).unwrap(); } #[test] @@ -284,6 +279,15 @@ mod tests { let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); let addr = encoder.parse_address_from_str(p2s_str).unwrap(); - let _script = addr.script().unwrap().proposition().unwrap(); + let _ = addr.script().unwrap().proposition().unwrap(); + // let ctx = Rc::new(force_any_val::()); + // let res = reduce_to_crypto(&script, &Env::empty(), ctx).unwrap(); + // match res.sigma_prop { + // SigmaBoolean::TrivialProp(b) => assert!(b), + // SigmaBoolean::ProofOfKnowledge(_) => { + // todo!() + // } + // SigmaBoolean::SigmaConjecture(_) => todo!(), + // } } } diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index f201a74f9..8202cd5c3 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -155,6 +155,14 @@ pub enum EvalError { /// Scorex serialization parsing error #[error("Serialization parsing error: {0}")] ScorexParsingError(#[from] ScorexParsingError), + /// Wrapped eval error with environment after evaluation + #[error("eval error: {error}, env: {env:?}")] + WrappedWithEnvError { + /// eval error + error: Box, + /// environment after evaluation + env: Env, + }, } /// Result of expression reduction procedure (see `reduce_to_crypto`). @@ -164,31 +172,39 @@ pub struct ReductionResult { pub sigma_prop: SigmaBoolean, /// estimated cost of expression evaluation pub cost: u64, - // pub env: Env, + /// environment after the evaluation + pub env: Env, } /// Evaluate the given expression by reducing it to SigmaBoolean value. pub fn reduce_to_crypto( expr: &Expr, - env: &mut Env, + env: &Env, ctx: Rc, ) -> Result { let cost_accum = CostAccumulator::new(0, None); let mut ectx = EvalContext::new(ctx, cost_accum); - expr.eval(env, &mut ectx) + let mut env_mut = env.clone(); + expr.eval(&mut env_mut, &mut ectx) .and_then(|v| -> Result { match v { Value::Boolean(b) => Ok(ReductionResult { sigma_prop: SigmaBoolean::TrivialProp(b), cost: 0, + env: env_mut.clone(), }), Value::SigmaProp(sp) => Ok(ReductionResult { sigma_prop: sp.value().clone(), cost: 0, + env: env_mut.clone(), }), _ => Err(EvalError::InvalidResultType), } }) + .map_err(|e| EvalError::WrappedWithEnvError { + error: Box::new(e), + env: env_mut, + }) } /// Expects SigmaProp constant value and returns it's value. Otherwise, returns an error. diff --git a/ergotree-interpreter/src/sigma_protocol/prover.rs b/ergotree-interpreter/src/sigma_protocol/prover.rs index 8549baeac..3f016b5e9 100644 --- a/ergotree-interpreter/src/sigma_protocol/prover.rs +++ b/ergotree-interpreter/src/sigma_protocol/prover.rs @@ -144,10 +144,7 @@ pub trait Prover { ) -> Result { let expr = tree.proposition()?; let ctx_ext = ctx.extension.clone(); - let mut env_mut = env.clone(); - let reduction_result = - reduce_to_crypto(&expr, &mut env_mut, ctx).map_err(ProverError::EvalError)?; - + let reduction_result = reduce_to_crypto(&expr, env, ctx).map_err(ProverError::EvalError)?; self.generate_proof(reduction_result.sigma_prop, message, hints_bag) .map(|p| ProverResult { proof: p, diff --git a/ergotree-interpreter/src/sigma_protocol/verifier.rs b/ergotree-interpreter/src/sigma_protocol/verifier.rs index 8101cbbc9..7219b9e68 100644 --- a/ergotree-interpreter/src/sigma_protocol/verifier.rs +++ b/ergotree-interpreter/src/sigma_protocol/verifier.rs @@ -66,8 +66,7 @@ pub trait Verifier { message: &[u8], ) -> Result { let expr = tree.proposition()?; - let mut env_mut = env.clone(); - let cprop = reduce_to_crypto(&expr, &mut env_mut, ctx)?.sigma_prop; + let cprop = reduce_to_crypto(&expr, env, ctx)?.sigma_prop; let res: bool = match cprop { SigmaBoolean::TrivialProp(b) => b, sb => { diff --git a/ergotree-ir/src/mir/val_def.rs b/ergotree-ir/src/mir/val_def.rs index 4858c5ad0..d213359f5 100644 --- a/ergotree-ir/src/mir/val_def.rs +++ b/ergotree-ir/src/mir/val_def.rs @@ -9,6 +9,7 @@ use crate::types::stype::SType; use super::expr::Expr; extern crate derive_more; +use derive_more::Display; use derive_more::From; use crate::has_opcode::HasStaticOpCode; @@ -16,7 +17,7 @@ use crate::has_opcode::HasStaticOpCode; use proptest_derive::Arbitrary; /// Variable id -#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, From)] +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, From, Display)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct ValId(pub u32); From 65b129d5ac46d45622c9170d6fff288d50f52161 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 19 Jul 2023 11:18:00 +0300 Subject: [PATCH 03/74] draft SourceSpan and SourceSpanWrapper; --- ergotree-interpreter/src/eval/coll_append.rs | 2 +- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 7 ++- ergotree-ir/src/mir/expr/source_span.rs | 57 ++++++++++++++++++++ ergotree-ir/src/serialization/expr.rs | 2 +- 5 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 ergotree-ir/src/mir/expr/source_span.rs diff --git a/ergotree-interpreter/src/eval/coll_append.rs b/ergotree-interpreter/src/eval/coll_append.rs index 7d02792fe..9e0f5a423 100644 --- a/ergotree-interpreter/src/eval/coll_append.rs +++ b/ergotree-interpreter/src/eval/coll_append.rs @@ -111,7 +111,7 @@ mod tests { fn append_byte_array_and_byte() { let byte_coll: Constant = vec![1i8, 2i8].into(); let byte: Expr = Expr::Collection(Collection::new(SType::SByte, vec![3i8.into()]).unwrap()); - let expr: Expr = Expr::Append(Append::new(byte_coll.into(), byte).unwrap()); + let expr: Expr = Expr::Append(Append::new(byte_coll.into(), byte).unwrap().into()); assert_eq!(eval_out_wo_ctx::>(&expr), vec![1i8, 2, 3]); } } diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 3439ff78c..8929c2ed2 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -50,7 +50,7 @@ impl Evaluable for Expr { Expr::Upcast(op) => op.eval(env, ctx), Expr::Downcast(op) => op.eval(env, ctx), Expr::If(op) => op.eval(env, ctx), - Expr::Append(op) => op.eval(env, ctx), + Expr::Append(op) => op.expr().eval(env, ctx), Expr::ByIndex(op) => op.eval(env, ctx), Expr::ExtractScriptBytes(op) => op.eval(env, ctx), Expr::SizeOf(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index d75cee57d..7b1943e65 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -80,11 +80,14 @@ use derive_more::From; use derive_more::TryInto; use thiserror::Error; +mod source_span; +pub use source_span::*; + #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)] /// Expression in ErgoTree pub enum Expr { /// Append - Concatenation of two collections - Append(Append), + Append(SourceSpanWrapper), /// Constant value Const(Constant), /// Placeholder for a constant @@ -227,7 +230,7 @@ impl Expr { /// Type of the expression pub fn tpe(&self) -> SType { match self { - Expr::Append(ap) => ap.tpe(), + Expr::Append(ap) => ap.expr().tpe(), Expr::Const(v) => v.tpe.clone(), Expr::Collection(v) => v.tpe(), Expr::SubstConstants(v) => v.tpe(), diff --git a/ergotree-ir/src/mir/expr/source_span.rs b/ergotree-ir/src/mir/expr/source_span.rs new file mode 100644 index 000000000..07cac9179 --- /dev/null +++ b/ergotree-ir/src/mir/expr/source_span.rs @@ -0,0 +1,57 @@ +use crate::mir::coll_append::Append; + +use super::Expr; + +/// Source position for the Expr +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SourceSpan { + /// Start position in the source code + pub start: usize, + /// End position in the source code + pub end: usize, +} + +impl SourceSpan { + /// Empty span + pub fn empty() -> Self { + SourceSpan { start: 0, end: 0 } + } +} + +/// Wrapper for Expr with source position +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SourceSpanWrapper { + /// Source position + pub source_span: SourceSpan, + /// Wrapped value + pub expr: T, +} + +impl SourceSpanWrapper { + /// Expression + pub fn expr(&self) -> &T { + &self.expr + } +} + +// TODO: can be a macros +impl From for Expr { + fn from(v: Append) -> Self { + Expr::Append(SourceSpanWrapper { + source_span: SourceSpan::empty(), + expr: v, + }) + } +} + +impl From for SourceSpanWrapper { + fn from(v: T) -> Self { + SourceSpanWrapper { + source_span: SourceSpan::empty(), + expr: v, + } + } +} + +// TODO: draft pretty printer and how it's sets source span for every expr +// TODO: draft enriching eval errors with source span and hightlight it in the source code piece diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index f4b97ba50..d9fe3355b 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -222,7 +222,7 @@ impl SigmaSerializable for Expr { } None => c.sigma_serialize(w), }, - Expr::Append(ap) => ap.sigma_serialize_w_opcode(w), + Expr::Append(ap) => ap.expr().sigma_serialize_w_opcode(w), Expr::Fold(op) => op.sigma_serialize_w_opcode(w), Expr::ConstPlaceholder(cp) => cp.sigma_serialize_w_opcode(w), Expr::SubstConstants(s) => s.sigma_serialize_w_opcode(w), From 35dd5acaa5a2e8dc78bcb0050dd173cb87bf7565 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 21 Jul 2023 11:27:48 +0300 Subject: [PATCH 04/74] enrich Append eval error with source span; --- ergotree-interpreter/src/eval.rs | 19 +++++++++++++++++++ ergotree-interpreter/src/eval/expr.rs | 13 ++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 8202cd5c3..1a5ebfcd5 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -1,6 +1,7 @@ //! Interpreter use bounded_vec::BoundedVecOutOfBounds; use ergotree_ir::mir::constant::TryExtractInto; +use ergotree_ir::mir::expr::SourceSpan; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use sigma_ser::ScorexParsingError; use sigma_ser::ScorexSerializationError; @@ -163,6 +164,24 @@ pub enum EvalError { /// environment after evaluation env: Env, }, + /// Wrapped eval error with source span + #[error("eval error: {error}, source span: {source_span:?}")] + WrappedWithSpan { + /// eval error + error: Box, + /// source span + source_span: SourceSpan, + }, +} + +impl EvalError { + /// Wrap eval error with source span + pub fn wrap_with_span(self, source_span: SourceSpan) -> Self { + EvalError::WrappedWithSpan { + error: Box::new(self), + source_span, + } + } } /// Result of expression reduction procedure (see `reduce_to_crypto`). diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 8929c2ed2..8dd436445 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -1,4 +1,5 @@ use ergotree_ir::mir::expr::Expr; +use ergotree_ir::mir::expr::SourceSpan; use ergotree_ir::mir::value::Value; use super::Env; @@ -50,7 +51,7 @@ impl Evaluable for Expr { Expr::Upcast(op) => op.eval(env, ctx), Expr::Downcast(op) => op.eval(env, ctx), Expr::If(op) => op.eval(env, ctx), - Expr::Append(op) => op.expr().eval(env, ctx), + Expr::Append(op) => op.expr().eval(env, ctx).with_span(&op.source_span), Expr::ByIndex(op) => op.eval(env, ctx), Expr::ExtractScriptBytes(op) => op.eval(env, ctx), Expr::SizeOf(op) => op.eval(env, ctx), @@ -83,3 +84,13 @@ impl Evaluable for Expr { } } } + +pub trait ExtResultEvalError { + fn with_span(self, span: &SourceSpan) -> Result; +} + +impl ExtResultEvalError for Result { + fn with_span(self, span: &SourceSpan) -> Result { + self.map_err(|e| e.wrap_with_span(span.clone())) + } +} From a96a7c967b4dc98775e2883c0a44dcf996a8108c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 24 Jul 2023 13:16:19 +0300 Subject: [PATCH 05/74] Move source_span module to the ergotree-ir crate root; rename SourceSpan to Span and wrapper to Spanned; --- ergotree-interpreter/src/eval.rs | 6 ++-- ergotree-interpreter/src/eval/expr.rs | 6 ++-- ergotree-ir/src/lib.rs | 1 + ergotree-ir/src/mir/expr.rs | 6 ++-- ergotree-ir/src/{mir/expr => }/source_span.rs | 30 +++++++++---------- 5 files changed, 23 insertions(+), 26 deletions(-) rename ergotree-ir/src/{mir/expr => }/source_span.rs (55%) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 1a5ebfcd5..dd9f03a9f 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -1,7 +1,7 @@ //! Interpreter use bounded_vec::BoundedVecOutOfBounds; use ergotree_ir::mir::constant::TryExtractInto; -use ergotree_ir::mir::expr::SourceSpan; +use ergotree_ir::mir::expr::Span; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; use sigma_ser::ScorexParsingError; use sigma_ser::ScorexSerializationError; @@ -170,13 +170,13 @@ pub enum EvalError { /// eval error error: Box, /// source span - source_span: SourceSpan, + source_span: Span, }, } impl EvalError { /// Wrap eval error with source span - pub fn wrap_with_span(self, source_span: SourceSpan) -> Self { + pub fn wrap_with_span(self, source_span: Span) -> Self { EvalError::WrappedWithSpan { error: Box::new(self), source_span, diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 8dd436445..074ec6bda 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -1,5 +1,5 @@ use ergotree_ir::mir::expr::Expr; -use ergotree_ir::mir::expr::SourceSpan; +use ergotree_ir::mir::expr::Span; use ergotree_ir::mir::value::Value; use super::Env; @@ -86,11 +86,11 @@ impl Evaluable for Expr { } pub trait ExtResultEvalError { - fn with_span(self, span: &SourceSpan) -> Result; + fn with_span(self, span: &Span) -> Result; } impl ExtResultEvalError for Result { - fn with_span(self, span: &SourceSpan) -> Result { + fn with_span(self, span: &Span) -> Result { self.map_err(|e| e.wrap_with_span(span.clone())) } } diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index 9f81748ec..b2ac46230 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -28,6 +28,7 @@ pub mod ergo_tree; pub mod mir; pub mod serialization; pub mod sigma_protocol; +pub mod source_span; pub mod type_check; pub mod types; pub mod util; diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 7b1943e65..f59b0cbb1 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -3,6 +3,7 @@ use std::convert::TryFrom; use std::convert::TryInto; +use crate::source_span::Spanned; use crate::types::stype::LiftIntoSType; use crate::types::stype::SType; @@ -80,14 +81,11 @@ use derive_more::From; use derive_more::TryInto; use thiserror::Error; -mod source_span; -pub use source_span::*; - #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)] /// Expression in ErgoTree pub enum Expr { /// Append - Concatenation of two collections - Append(SourceSpanWrapper), + Append(Spanned), /// Constant value Const(Constant), /// Placeholder for a constant diff --git a/ergotree-ir/src/mir/expr/source_span.rs b/ergotree-ir/src/source_span.rs similarity index 55% rename from ergotree-ir/src/mir/expr/source_span.rs rename to ergotree-ir/src/source_span.rs index 07cac9179..6e1930a6b 100644 --- a/ergotree-ir/src/mir/expr/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,33 +1,34 @@ -use crate::mir::coll_append::Append; +//! Source position for an IR node in the source code -use super::Expr; +use crate::mir::coll_append::Append; +use crate::mir::expr::Expr; /// Source position for the Expr #[derive(PartialEq, Eq, Debug, Clone)] -pub struct SourceSpan { +pub struct Span { /// Start position in the source code pub start: usize, /// End position in the source code pub end: usize, } -impl SourceSpan { +impl Span { /// Empty span pub fn empty() -> Self { - SourceSpan { start: 0, end: 0 } + Span { start: 0, end: 0 } } } /// Wrapper for Expr with source position #[derive(PartialEq, Eq, Debug, Clone)] -pub struct SourceSpanWrapper { +pub struct Spanned { /// Source position - pub source_span: SourceSpan, + pub source_span: Span, /// Wrapped value pub expr: T, } -impl SourceSpanWrapper { +impl Spanned { /// Expression pub fn expr(&self) -> &T { &self.expr @@ -37,21 +38,18 @@ impl SourceSpanWrapper { // TODO: can be a macros impl From for Expr { fn from(v: Append) -> Self { - Expr::Append(SourceSpanWrapper { - source_span: SourceSpan::empty(), + Expr::Append(Spanned { + source_span: Span::empty(), expr: v, }) } } -impl From for SourceSpanWrapper { +impl From for Spanned { fn from(v: T) -> Self { - SourceSpanWrapper { - source_span: SourceSpan::empty(), + Spanned { + source_span: Span::empty(), expr: v, } } } - -// TODO: draft pretty printer and how it's sets source span for every expr -// TODO: draft enriching eval errors with source span and hightlight it in the source code piece From eda5e274e63f5d4561f8be6116b14c7cd6f5a238 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 24 Jul 2023 13:42:29 +0300 Subject: [PATCH 06/74] draft pretty printer types and smoke test; --- ergotree-ir/Cargo.toml | 9 ++--- ergotree-ir/src/lib.rs | 1 + ergotree-ir/src/pretty_printer.rs | 62 +++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 ergotree-ir/src/pretty_printer.rs diff --git a/ergotree-ir/Cargo.toml b/ergotree-ir/Cargo.toml index 7711bdaf5..8d2a78879 100644 --- a/ergotree-ir/Cargo.toml +++ b/ergotree-ir/Cargo.toml @@ -6,9 +6,7 @@ authors = ["Denys Zadorozhnyi "] repository.workspace = true edition.workspace = true description = "ErgoTree IR, serialization" -exclude = [ - "proptest-regressions/*" -] +exclude = ["proptest-regressions/*"] [lib] crate-type = ["cdylib", "rlib"] @@ -22,7 +20,7 @@ elliptic-curve = { workspace = true } thiserror = { workspace = true } lazy_static = { workspace = true } derive_more = { workspace = true } -proptest = { workspace = true , optional = true } +proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } bs58 = { workspace = true } base16 = { workspace = true } @@ -32,7 +30,7 @@ num-traits = { workspace = true } num-derive = { workspace = true } num-integer = { workspace = true } indexmap = { workspace = true } -serde = { workspace = true , optional = true } +serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } serde_with = { workspace = true, optional = true } num256 = "0.3.1" @@ -49,3 +47,4 @@ json = ["serde", "serde_json", "serde_with", "bounded-vec/serde"] sigma-test-util = { workspace = true } rand = { workspace = true } pretty_assertions = { workspace = true } +expect-test = { workspace = true } diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index b2ac46230..872c3fa42 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -32,3 +32,4 @@ pub mod source_span; pub mod type_check; pub mod types; pub mod util; +mod pretty_printer; diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs new file mode 100644 index 000000000..c5d93a00d --- /dev/null +++ b/ergotree-ir/src/pretty_printer.rs @@ -0,0 +1,62 @@ +use crate::mir::expr::Expr; + +pub(crate) struct PrintExpr { + expr: Expr, + text: String, +} + +#[derive(PartialEq, Eq, Debug, Clone)] +pub(crate) enum PrintError {} + +#[allow(clippy::todo)] +pub(crate) fn print_expr(expr: Expr) -> Result { + todo!() +} + +#[allow(clippy::unwrap_used)] +#[cfg(test)] +mod tests { + + use expect_test::expect; + + use crate::mir::block::BlockValue; + use crate::mir::val_def::ValDef; + use crate::mir::val_use::ValUse; + use crate::types::stype::SType; + + use super::*; + + fn check(expr: Expr, expected_tree: expect_test::Expect) { + let expected_out = print_expr(expr).unwrap(); + expected_tree.assert_eq(&expected_out.text); + } + + #[test] + fn smoke() { + let val_id = 2.into(); + let body = Expr::BlockValue(BlockValue { + items: vec![ValDef { + id: val_id, + rhs: Box::new(Expr::Const(1i32.into())), + } + .into()], + result: Box::new( + ValUse { + val_id, + tpe: SType::SInt, + } + .into(), + ), + }); + let expr = Expr::Const(1i32.into()); + check( + expr, + expect![[r#" + { + val v1 = 1 + v1 + } + "#]], + ); + } +} From 8b3d624dca96526f094ccb6cc108a88f5db60031 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 24 Jul 2023 16:13:16 +0300 Subject: [PATCH 07/74] draft Print trait IR nodes; --- ergotree-ir/src/pretty_printer.rs | 54 ++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index c5d93a00d..d46feb4b8 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -1,16 +1,54 @@ +use std::fmt::Write; + +use crate::mir::coll_append::Append; use crate::mir::expr::Expr; +use crate::source_span::Span; +use crate::source_span::Spanned; pub(crate) struct PrintExpr { - expr: Expr, + spanned_expr: Expr, text: String, } #[derive(PartialEq, Eq, Debug, Clone)] pub(crate) enum PrintError {} -#[allow(clippy::todo)] -pub(crate) fn print_expr(expr: Expr) -> Result { - todo!() +struct PrintContext { + current_pos: usize, + current_indent: usize, +} + +trait Print { + fn print(&self, w: &mut dyn Write, pc: &mut PrintContext) -> Result; +} + +impl Print for Append { + fn print(&self, w: &mut dyn Write, pc: &mut PrintContext) -> Result { + let start_pos = pc.current_pos; + self.input.print(w, pc)?; + // TODO: set indent + write!(w, ".append(")?; + // TODO: need a custom writer to bundle output and moving current pos + pc.current_pos += 8; + self.col_2.print(w, pc)?; + write!(w, ")")?; + pc.current_pos += 1; + let end_pos = pc.current_pos; + Ok(Spanned { + source_span: Span { + start: start_pos, + end: end_pos, + }, + expr: self.clone(), + } + .into()) + } +} + +impl Print for Expr { + fn print(&self, w: &mut dyn Write, pc: &mut PrintContext) -> Result { + todo!() + } } #[allow(clippy::unwrap_used)] @@ -27,7 +65,13 @@ mod tests { use super::*; fn check(expr: Expr, expected_tree: expect_test::Expect) { - let expected_out = print_expr(expr).unwrap(); + // TODO: create a formatter and grab it's output + let expected_out = todo!(); + let mut pc = PrintContext { + current_pos: 0, + current_indent: 0, + }; + let spanned_expr = expr.print(w, &mut pc).unwrap(); expected_tree.assert_eq(&expected_out.text); } From 7a562f70dce6f6a85dede5f5fa50edcab02b7618 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 1 Aug 2023 12:20:46 +0300 Subject: [PATCH 08/74] draft Printer trait tracking current position and indentation level; --- ergotree-ir/src/pretty_printer.rs | 98 +++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index d46feb4b8..55e18b197 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -1,39 +1,30 @@ use std::fmt::Write; +use thiserror::Error; + use crate::mir::coll_append::Append; use crate::mir::expr::Expr; use crate::source_span::Span; use crate::source_span::Spanned; -pub(crate) struct PrintExpr { - spanned_expr: Expr, - text: String, -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub(crate) enum PrintError {} - -struct PrintContext { - current_pos: usize, - current_indent: usize, +#[derive(PartialEq, Eq, Debug, Clone, Error)] +pub(crate) enum PrintError { + #[error("fmt error: {0:?}")] + FmtError(#[from] std::fmt::Error), } trait Print { - fn print(&self, w: &mut dyn Write, pc: &mut PrintContext) -> Result; + fn print(&self, w: &mut dyn Printer) -> Result; } impl Print for Append { - fn print(&self, w: &mut dyn Write, pc: &mut PrintContext) -> Result { - let start_pos = pc.current_pos; - self.input.print(w, pc)?; - // TODO: set indent + fn print(&self, w: &mut dyn Printer) -> Result { + let start_pos = w.current_pos(); + self.input.print(w)?; write!(w, ".append(")?; - // TODO: need a custom writer to bundle output and moving current pos - pc.current_pos += 8; - self.col_2.print(w, pc)?; + self.col_2.print(w)?; write!(w, ")")?; - pc.current_pos += 1; - let end_pos = pc.current_pos; + let end_pos = w.current_pos(); Ok(Spanned { source_span: Span { start: start_pos, @@ -46,11 +37,65 @@ impl Print for Append { } impl Print for Expr { - fn print(&self, w: &mut dyn Write, pc: &mut PrintContext) -> Result { + fn print(&self, w: &mut dyn Printer) -> Result { todo!() } } +// TODO: extract to a separate module +pub trait Printer: Write { + fn current_pos(&self) -> usize; + fn inc_ident(&mut self); + fn dec_ident(&mut self); +} + +pub struct PosTrackingWriter { + print_buf: String, + current_pos: usize, + current_indent: usize, +} + +impl Write for PosTrackingWriter { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + let indented_str = s + .lines() + .map(|l| { + let mut indent = String::new(); + for _ in 0..self.current_indent { + indent.push(' '); + } + format!("{}{}", indent, l) + }) + .collect::>() + .join("\n"); + let len = s.len(); + self.current_pos += len; + write!(self.print_buf, "{}", indented_str) + } +} + +impl Printer for PosTrackingWriter { + fn current_pos(&self) -> usize { + self.current_pos + } + + fn inc_ident(&mut self) { + self.current_indent += Self::INDENT; + } + + fn dec_ident(&mut self) { + self.current_indent -= Self::INDENT; + } +} + +impl PosTrackingWriter { + const INDENT: usize = 4; + + fn get_buf(&self) -> &str { + &self.print_buf + } +} + #[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { @@ -66,13 +111,14 @@ mod tests { fn check(expr: Expr, expected_tree: expect_test::Expect) { // TODO: create a formatter and grab it's output - let expected_out = todo!(); - let mut pc = PrintContext { + let print_buf = String::new(); + let mut w = PosTrackingWriter { + print_buf, current_pos: 0, current_indent: 0, }; - let spanned_expr = expr.print(w, &mut pc).unwrap(); - expected_tree.assert_eq(&expected_out.text); + let spanned_expr = expr.print(&mut w).unwrap(); + expected_tree.assert_eq(w.get_buf()); } #[test] From 7f28707cf1def05cf8515b4d4433f3ad635778df Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 2 Aug 2023 12:23:42 +0300 Subject: [PATCH 09/74] draft Print impl for Expr; --- ergotree-ir/src/pretty_printer.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 55e18b197..948161b91 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -36,9 +36,13 @@ impl Print for Append { } } +#[allow(clippy::todo)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { - todo!() + match self { + Expr::Append(a) => a.expr().print(w), + _ => todo!(), + } } } From 868076bf42ebea94659314d360a38d869d7b38a8 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 2 Aug 2023 12:49:08 +0300 Subject: [PATCH 10/74] draft the expr printing and running eval again in reduce_to_crypto; --- ergotree-interpreter/src/eval.rs | 67 +++++++++++++++++---------- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/lib.rs | 2 +- ergotree-ir/src/pretty_printer.rs | 33 +++++++++++-- 4 files changed, 75 insertions(+), 29 deletions(-) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index dd9f03a9f..09e2f72ab 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -1,8 +1,10 @@ //! Interpreter use bounded_vec::BoundedVecOutOfBounds; use ergotree_ir::mir::constant::TryExtractInto; -use ergotree_ir::mir::expr::Span; +use ergotree_ir::pretty_printer::PosTrackingWriter; +use ergotree_ir::pretty_printer::Print; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; +use ergotree_ir::source_span::Span; use sigma_ser::ScorexParsingError; use sigma_ser::ScorexSerializationError; use std::rc::Rc; @@ -201,29 +203,46 @@ pub fn reduce_to_crypto( env: &Env, ctx: Rc, ) -> Result { - let cost_accum = CostAccumulator::new(0, None); - let mut ectx = EvalContext::new(ctx, cost_accum); - let mut env_mut = env.clone(); - expr.eval(&mut env_mut, &mut ectx) - .and_then(|v| -> Result { - match v { - Value::Boolean(b) => Ok(ReductionResult { - sigma_prop: SigmaBoolean::TrivialProp(b), - cost: 0, - env: env_mut.clone(), - }), - Value::SigmaProp(sp) => Ok(ReductionResult { - sigma_prop: sp.value().clone(), - cost: 0, - env: env_mut.clone(), - }), - _ => Err(EvalError::InvalidResultType), - } - }) - .map_err(|e| EvalError::WrappedWithEnvError { - error: Box::new(e), - env: env_mut, - }) + let env_clone = env.clone(); + let ctx_clone = ctx.clone(); + fn inner(expr: &Expr, env: &Env, ctx: Rc) -> Result { + let cost_accum = CostAccumulator::new(0, None); + let mut ectx = EvalContext::new(ctx, cost_accum); + let mut env_mut = env.clone(); + expr.eval(&mut env_mut, &mut ectx) + .and_then(|v| -> Result { + match v { + Value::Boolean(b) => Ok(ReductionResult { + sigma_prop: SigmaBoolean::TrivialProp(b), + cost: 0, + env: env_mut.clone(), + }), + Value::SigmaProp(sp) => Ok(ReductionResult { + sigma_prop: sp.value().clone(), + cost: 0, + env: env_mut.clone(), + }), + _ => Err(EvalError::InvalidResultType), + } + }) + } + + let res = inner(expr, env, ctx); + if res.is_ok() { + return res; + } + + let mut printer = PosTrackingWriter::new(); + let spanned_expr = expr + .print(&mut printer) + .map_err(|e| EvalError::Misc(format!("printer error: {}", e)))?; + let printed_expr_str = printer.get_buf(); + // TODO: cut the part of the printed_expr_str relevant to the span of the expr where error was generated + // and include it in the returned error + inner(&spanned_expr, env, ctx_clone).map_err(|e| EvalError::WrappedWithEnvError { + error: Box::new(e), + env: env_clone, + }) } /// Expects SigmaProp constant value and returns it's value. Otherwise, returns an error. diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 074ec6bda..24e0d233c 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -1,6 +1,6 @@ use ergotree_ir::mir::expr::Expr; -use ergotree_ir::mir::expr::Span; use ergotree_ir::mir::value::Value; +use ergotree_ir::source_span::Span; use super::Env; use super::EvalContext; diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index 872c3fa42..1bc1c274a 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -32,4 +32,4 @@ pub mod source_span; pub mod type_check; pub mod types; pub mod util; -mod pretty_printer; +pub mod pretty_printer; diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 948161b91..cc68e5411 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -1,3 +1,5 @@ +//! Pretty printer for ErgoTree IR + use std::fmt::Write; use thiserror::Error; @@ -7,13 +9,17 @@ use crate::mir::expr::Expr; use crate::source_span::Span; use crate::source_span::Spanned; +/// Print error +#[allow(missing_docs)] #[derive(PartialEq, Eq, Debug, Clone, Error)] -pub(crate) enum PrintError { +pub enum PrintError { #[error("fmt error: {0:?}")] FmtError(#[from] std::fmt::Error), } -trait Print { +/// Print trait for Expr that sets the source span for the resulting Expr +pub trait Print { + /// Print the expression and return the resulting expression with source span fn print(&self, w: &mut dyn Printer) -> Result; } @@ -47,12 +53,17 @@ impl Print for Expr { } // TODO: extract to a separate module +/// Printer trait with tracking of current position and indent pub trait Printer: Write { + /// Current position (last printed char) fn current_pos(&self) -> usize; + /// Increase indent fn inc_ident(&mut self); + /// Decrease indent fn dec_ident(&mut self); } +/// Printer implementation with tracking of current position and indent pub struct PosTrackingWriter { print_buf: String, current_pos: usize, @@ -95,11 +106,27 @@ impl Printer for PosTrackingWriter { impl PosTrackingWriter { const INDENT: usize = 4; - fn get_buf(&self) -> &str { + /// Create new printer + pub fn new() -> Self { + Self { + print_buf: String::new(), + current_pos: 0, + current_indent: 0, + } + } + + /// Get printed buffer + pub fn get_buf(&self) -> &str { &self.print_buf } } +impl Default for PosTrackingWriter { + fn default() -> Self { + Self::new() + } +} + #[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { From e46c92ee66b311d4f972bd09d4ec286a9f4ae67c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 3 Aug 2023 10:25:28 +0300 Subject: [PATCH 11/74] extract EvalError into a separate module; --- ergotree-interpreter/src/eval.rs | 93 +------------------------ ergotree-interpreter/src/eval/error.rs | 94 ++++++++++++++++++++++++++ ergotree-interpreter/src/eval/expr.rs | 1 + 3 files changed, 97 insertions(+), 91 deletions(-) create mode 100644 ergotree-interpreter/src/eval/error.rs diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 09e2f72ab..ba2acee8d 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -1,28 +1,18 @@ //! Interpreter -use bounded_vec::BoundedVecOutOfBounds; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::pretty_printer::PosTrackingWriter; use ergotree_ir::pretty_printer::Print; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp; -use ergotree_ir::source_span::Span; -use sigma_ser::ScorexParsingError; -use sigma_ser::ScorexSerializationError; use std::rc::Rc; -use ergotree_ir::ergo_tree::ErgoTreeError; -use ergotree_ir::mir::constant::TryExtractFromError; use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; -use ergotree_ir::serialization::SigmaParsingError; -use ergotree_ir::serialization::SigmaSerializationError; use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean; use cost_accum::CostAccumulator; use ergotree_ir::types::smethod::SMethod; -use thiserror::Error; use self::context::Context; -use self::cost_accum::CostError; use self::env::Env; /// Context(blockchain) for the interpreter @@ -60,6 +50,7 @@ pub(crate) mod decode_point; mod deserialize_context; mod deserialize_register; pub(crate) mod downcast; +mod error; pub(crate) mod exponentiate; pub(crate) mod expr; pub(crate) mod extract_amount; @@ -104,87 +95,7 @@ pub(crate) mod val_use; pub(crate) mod xor; pub(crate) mod xor_of; -/// Interpreter errors -#[derive(Error, PartialEq, Eq, Debug, Clone)] -pub enum EvalError { - /// AVL tree errors - #[error("AvlTree: {0}")] - AvlTree(String), - /// Only boolean or SigmaBoolean is a valid result expr type - #[error("Only boolean or SigmaBoolean is a valid result expr type")] - InvalidResultType, - /// Unexpected Expr encountered during the evaluation - #[error("Unexpected Expr: {0}")] - UnexpectedExpr(String), - /// Error on cost calculation - #[error("Error on cost calculation: {0:?}")] - CostError(#[from] CostError), - /// Unexpected value type - #[error("Unexpected value type: {0:?}")] - TryExtractFrom(#[from] TryExtractFromError), - /// Not found (missing value, argument, etc.) - #[error("Not found: {0}")] - NotFound(String), - /// Register id out of bounds - #[error("{0}")] - RegisterIdOutOfBounds(String), - /// Unexpected value - #[error("Unexpected value: {0}")] - UnexpectedValue(String), - /// Arithmetic exception error - #[error("Arithmetic exception: {0}")] - ArithmeticException(String), - /// Misc error - #[error("error: {0}")] - Misc(String), - /// Sigma serialization error - #[error("Serialization error: {0}")] - SigmaSerializationError(#[from] SigmaSerializationError), - /// Sigma serialization parsing error - #[error("Serialization parsing error: {0}")] - SigmaParsingError(#[from] SigmaParsingError), - /// ErgoTree error - #[error("ErgoTree error: {0}")] - ErgoTreeError(#[from] ErgoTreeError), - /// Not yet implemented - #[error("evaluation is not yet implemented: {0}")] - NotImplementedYet(&'static str), - /// Invalid item quantity for BoundedVec - #[error("Invalid item quantity for BoundedVec: {0}")] - BoundedVecError(#[from] BoundedVecOutOfBounds), - /// Scorex serialization error - #[error("Serialization error: {0}")] - ScorexSerializationError(#[from] ScorexSerializationError), - /// Scorex serialization parsing error - #[error("Serialization parsing error: {0}")] - ScorexParsingError(#[from] ScorexParsingError), - /// Wrapped eval error with environment after evaluation - #[error("eval error: {error}, env: {env:?}")] - WrappedWithEnvError { - /// eval error - error: Box, - /// environment after evaluation - env: Env, - }, - /// Wrapped eval error with source span - #[error("eval error: {error}, source span: {source_span:?}")] - WrappedWithSpan { - /// eval error - error: Box, - /// source span - source_span: Span, - }, -} - -impl EvalError { - /// Wrap eval error with source span - pub fn wrap_with_span(self, source_span: Span) -> Self { - EvalError::WrappedWithSpan { - error: Box::new(self), - source_span, - } - } -} +pub use error::EvalError; /// Result of expression reduction procedure (see `reduce_to_crypto`). #[derive(PartialEq, Eq, Debug, Clone)] diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs new file mode 100644 index 000000000..08985f944 --- /dev/null +++ b/ergotree-interpreter/src/eval/error.rs @@ -0,0 +1,94 @@ +use bounded_vec::BoundedVecOutOfBounds; +use ergotree_ir::ergo_tree::ErgoTreeError; +use ergotree_ir::mir::constant::TryExtractFromError; +use ergotree_ir::serialization::SigmaParsingError; +use ergotree_ir::serialization::SigmaSerializationError; +use ergotree_ir::source_span::Span; +use sigma_ser::ScorexParsingError; +use sigma_ser::ScorexSerializationError; +use thiserror::Error; + +use super::cost_accum::CostError; +use super::env::Env; + +/// Interpreter errors +#[derive(Error, PartialEq, Eq, Debug, Clone)] +pub enum EvalError { + /// AVL tree errors + #[error("AvlTree: {0}")] + AvlTree(String), + /// Only boolean or SigmaBoolean is a valid result expr type + #[error("Only boolean or SigmaBoolean is a valid result expr type")] + InvalidResultType, + /// Unexpected Expr encountered during the evaluation + #[error("Unexpected Expr: {0}")] + UnexpectedExpr(String), + /// Error on cost calculation + #[error("Error on cost calculation: {0:?}")] + CostError(#[from] CostError), + /// Unexpected value type + #[error("Unexpected value type: {0:?}")] + TryExtractFrom(#[from] TryExtractFromError), + /// Not found (missing value, argument, etc.) + #[error("Not found: {0}")] + NotFound(String), + /// Register id out of bounds + #[error("{0}")] + RegisterIdOutOfBounds(String), + /// Unexpected value + #[error("Unexpected value: {0}")] + UnexpectedValue(String), + /// Arithmetic exception error + #[error("Arithmetic exception: {0}")] + ArithmeticException(String), + /// Misc error + #[error("error: {0}")] + Misc(String), + /// Sigma serialization error + #[error("Serialization error: {0}")] + SigmaSerializationError(#[from] SigmaSerializationError), + /// Sigma serialization parsing error + #[error("Serialization parsing error: {0}")] + SigmaParsingError(#[from] SigmaParsingError), + /// ErgoTree error + #[error("ErgoTree error: {0}")] + ErgoTreeError(#[from] ErgoTreeError), + /// Not yet implemented + #[error("evaluation is not yet implemented: {0}")] + NotImplementedYet(&'static str), + /// Invalid item quantity for BoundedVec + #[error("Invalid item quantity for BoundedVec: {0}")] + BoundedVecError(#[from] BoundedVecOutOfBounds), + /// Scorex serialization error + #[error("Serialization error: {0}")] + ScorexSerializationError(#[from] ScorexSerializationError), + /// Scorex serialization parsing error + #[error("Serialization parsing error: {0}")] + ScorexParsingError(#[from] ScorexParsingError), + /// Wrapped eval error with environment after evaluation + #[error("eval error: {error}, env: {env:?}")] + WrappedWithEnvError { + /// eval error + error: Box, + /// environment after evaluation + env: Env, + }, + /// Wrapped eval error with source span + #[error("eval error: {error}, source span: {source_span:?}")] + WrappedWithSpan { + /// eval error + error: Box, + /// source span + source_span: Span, + }, +} + +impl EvalError { + /// Wrap eval error with source span + pub fn wrap_with_span(self, source_span: Span) -> Self { + EvalError::WrappedWithSpan { + error: Box::new(self), + source_span, + } + } +} diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 24e0d233c..5a679dd11 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -85,6 +85,7 @@ impl Evaluable for Expr { } } +// TODO: extract pub trait ExtResultEvalError { fn with_span(self, span: &Span) -> Result; } From e20f0879c21bd3c0d5af43ad90490be63f5929cc Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 3 Aug 2023 10:43:20 +0300 Subject: [PATCH 12/74] merge wrapped EvalError variants into one; --- ergotree-interpreter/src/eval.rs | 5 +- ergotree-interpreter/src/eval/error.rs | 31 ++++++----- ergotree-interpreter/src/eval/expr.rs | 20 ++----- ergotree-ir/src/source_span.rs | 75 ++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 32 deletions(-) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index ba2acee8d..5f4e1c902 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -150,10 +150,7 @@ pub fn reduce_to_crypto( let printed_expr_str = printer.get_buf(); // TODO: cut the part of the printed_expr_str relevant to the span of the expr where error was generated // and include it in the returned error - inner(&spanned_expr, env, ctx_clone).map_err(|e| EvalError::WrappedWithEnvError { - error: Box::new(e), - env: env_clone, - }) + inner(&spanned_expr, env, ctx_clone) } /// Expects SigmaProp constant value and returns it's value. Otherwise, returns an error. diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 08985f944..83247a68f 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -65,30 +65,35 @@ pub enum EvalError { /// Scorex serialization parsing error #[error("Serialization parsing error: {0}")] ScorexParsingError(#[from] ScorexParsingError), - /// Wrapped eval error with environment after evaluation - #[error("eval error: {error}, env: {env:?}")] - WrappedWithEnvError { - /// eval error - error: Box, - /// environment after evaluation - env: Env, - }, - /// Wrapped eval error with source span - #[error("eval error: {error}, source span: {source_span:?}")] - WrappedWithSpan { + /// Wrapped error with source span and environment + #[error("eval error: {error}, source span: {source_span:?}, env: {env:?}")] + Wrapped { /// eval error error: Box, /// source span source_span: Span, + /// environment after evaluation + env: Env, }, } impl EvalError { /// Wrap eval error with source span - pub fn wrap_with_span(self, source_span: Span) -> Self { - EvalError::WrappedWithSpan { + pub fn wrap(self, source_span: Span, env: Env) -> Self { + EvalError::Wrapped { error: Box::new(self), source_span, + env, } } } + +pub trait ExtResultEvalError { + fn enrich_err(self, span: Span, env: Env) -> Result; +} + +impl ExtResultEvalError for Result { + fn enrich_err(self, span: Span, env: Env) -> Result { + self.map_err(|e| e.wrap(span, env)) + } +} diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 5a679dd11..b0b23e71f 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -1,7 +1,7 @@ use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; -use ergotree_ir::source_span::Span; +use super::error::ExtResultEvalError; use super::Env; use super::EvalContext; use super::EvalError; @@ -10,7 +10,7 @@ use super::Evaluable; impl Evaluable for Expr { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { ctx.cost_accum.add_cost_of(self)?; - match self { + let res = match self { Expr::Const(c) => Ok(Value::from(c.v.clone())), Expr::SubstConstants(op) => op.eval(env, ctx), Expr::ByteArrayToLong(op) => op.eval(env, ctx), @@ -51,7 +51,7 @@ impl Evaluable for Expr { Expr::Upcast(op) => op.eval(env, ctx), Expr::Downcast(op) => op.eval(env, ctx), Expr::If(op) => op.eval(env, ctx), - Expr::Append(op) => op.expr().eval(env, ctx).with_span(&op.source_span), + Expr::Append(op) => op.expr().eval(env, ctx), Expr::ByIndex(op) => op.eval(env, ctx), Expr::ExtractScriptBytes(op) => op.eval(env, ctx), Expr::SizeOf(op) => op.eval(env, ctx), @@ -81,17 +81,7 @@ impl Evaluable for Expr { Expr::ExtractBytesWithNoRef(op) => op.eval(env, ctx), Expr::TreeLookup(op) => op.eval(env, ctx), Expr::CreateAvlTree(op) => op.eval(env, ctx), - } - } -} - -// TODO: extract -pub trait ExtResultEvalError { - fn with_span(self, span: &Span) -> Result; -} - -impl ExtResultEvalError for Result { - fn with_span(self, span: &Span) -> Result { - self.map_err(|e| e.wrap_with_span(span.clone())) + }; + res.enrich_err(self.span().clone(), env.clone()) } } diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 6e1930a6b..94abe8a37 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -53,3 +53,78 @@ impl From for Spanned { } } } + +impl Expr { + /// Source span for the Expr + #[allow(clippy::todo)] + pub fn span(&self) -> &Span { + match self { + Expr::Append(op) => &op.source_span, + Expr::Const(_) => todo!(), + Expr::ConstPlaceholder(_) => todo!(), + Expr::SubstConstants(_) => todo!(), + Expr::ByteArrayToLong(_) => todo!(), + Expr::ByteArrayToBigInt(_) => todo!(), + Expr::LongToByteArray(_) => todo!(), + Expr::Collection(_) => todo!(), + Expr::Tuple(_) => todo!(), + Expr::CalcBlake2b256(_) => todo!(), + Expr::CalcSha256(_) => todo!(), + Expr::Context => todo!(), + Expr::Global => todo!(), + Expr::GlobalVars(_) => todo!(), + Expr::FuncValue(_) => todo!(), + Expr::Apply(_) => todo!(), + Expr::MethodCall(_) => todo!(), + Expr::ProperyCall(_) => todo!(), + Expr::BlockValue(_) => todo!(), + Expr::ValDef(_) => todo!(), + Expr::ValUse(_) => todo!(), + Expr::If(_) => todo!(), + Expr::BinOp(_) => todo!(), + Expr::And(_) => todo!(), + Expr::Or(_) => todo!(), + Expr::Xor(_) => todo!(), + Expr::Atleast(_) => todo!(), + Expr::LogicalNot(_) => todo!(), + Expr::Negation(_) => todo!(), + Expr::BitInversion(_) => todo!(), + Expr::OptionGet(_) => todo!(), + Expr::OptionIsDefined(_) => todo!(), + Expr::OptionGetOrElse(_) => todo!(), + Expr::ExtractAmount(_) => todo!(), + Expr::ExtractRegisterAs(_) => todo!(), + Expr::ExtractBytes(_) => todo!(), + Expr::ExtractBytesWithNoRef(_) => todo!(), + Expr::ExtractScriptBytes(_) => todo!(), + Expr::ExtractCreationInfo(_) => todo!(), + Expr::ExtractId(_) => todo!(), + Expr::ByIndex(_) => todo!(), + Expr::SizeOf(_) => todo!(), + Expr::Slice(_) => todo!(), + Expr::Fold(_) => todo!(), + Expr::Map(_) => todo!(), + Expr::Filter(_) => todo!(), + Expr::Exists(_) => todo!(), + Expr::ForAll(_) => todo!(), + Expr::SelectField(_) => todo!(), + Expr::BoolToSigmaProp(_) => todo!(), + Expr::Upcast(_) => todo!(), + Expr::Downcast(_) => todo!(), + Expr::CreateProveDlog(_) => todo!(), + Expr::CreateProveDhTuple(_) => todo!(), + Expr::SigmaPropBytes(_) => todo!(), + Expr::DecodePoint(_) => todo!(), + Expr::SigmaAnd(_) => todo!(), + Expr::SigmaOr(_) => todo!(), + Expr::GetVar(_) => todo!(), + Expr::DeserializeRegister(_) => todo!(), + Expr::DeserializeContext(_) => todo!(), + Expr::MultiplyGroup(_) => todo!(), + Expr::Exponentiate(_) => todo!(), + Expr::XorOf(_) => todo!(), + Expr::TreeLookup(_) => todo!(), + Expr::CreateAvlTree(_) => todo!(), + } + } +} From 01cb82f7a72d34349e722a47af6a08b2f83a7d92 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 3 Aug 2023 10:53:16 +0300 Subject: [PATCH 13/74] extract EvalErrorDetails and add wrap_with_src for EvalError; --- ergotree-interpreter/src/eval.rs | 5 +-- ergotree-interpreter/src/eval/error.rs | 47 ++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 5f4e1c902..dfb93aeb5 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -142,15 +142,12 @@ pub fn reduce_to_crypto( if res.is_ok() { return res; } - let mut printer = PosTrackingWriter::new(); let spanned_expr = expr .print(&mut printer) .map_err(|e| EvalError::Misc(format!("printer error: {}", e)))?; let printed_expr_str = printer.get_buf(); - // TODO: cut the part of the printed_expr_str relevant to the span of the expr where error was generated - // and include it in the returned error - inner(&spanned_expr, env, ctx_clone) + inner(&spanned_expr, env, ctx_clone).map_err(|e| e.wrap_with_src(printed_expr_str.to_string())) } /// Expects SigmaProp constant value and returns it's value. Otherwise, returns an error. diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 83247a68f..8bda2d865 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -66,24 +66,57 @@ pub enum EvalError { #[error("Serialization parsing error: {0}")] ScorexParsingError(#[from] ScorexParsingError), /// Wrapped error with source span and environment - #[error("eval error: {error}, source span: {source_span:?}, env: {env:?}")] + #[error("eval error: {error}, details: {details:?}")] Wrapped { /// eval error error: Box, - /// source span - source_span: Span, - /// environment after evaluation - env: Env, + /// error details + details: EvalErrorDetails, }, } +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct EvalErrorDetails { + /// source span + source_span: Span, + /// environment after evaluation + env: Env, + /// source code + source: Option, +} + impl EvalError { /// Wrap eval error with source span pub fn wrap(self, source_span: Span, env: Env) -> Self { EvalError::Wrapped { error: Box::new(self), - source_span, - env, + details: EvalErrorDetails { + source_span, + env, + source: None, + }, + } + } + + /// Wrap eval error with source code + pub fn wrap_with_src(self, source: String) -> Self { + match self { + EvalError::Wrapped { error, details } => EvalError::Wrapped { + error, + details: EvalErrorDetails { + source_span: details.source_span, + env: details.env, + source: Some(source), + }, + }, + e => EvalError::Wrapped { + error: Box::new(e), + details: EvalErrorDetails { + source_span: Span::empty(), + env: Env::empty(), + source: Some(source), + }, + }, } } } From c99f6ce85a0d5401e7553e1e6ed02b9e615cd221 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 4 Aug 2023 11:20:48 +0300 Subject: [PATCH 14/74] impl Print for BlockValue; --- ergotree-interpreter/src/eval.rs | 1 - ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/block.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 +- ergotree-ir/src/pretty_printer.rs | 71 +++++++++++++++++---------- ergotree-ir/src/serialization/expr.rs | 4 +- ergotree-ir/src/source_span.rs | 23 ++++++--- 7 files changed, 67 insertions(+), 40 deletions(-) diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index dfb93aeb5..3fcf703b6 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -114,7 +114,6 @@ pub fn reduce_to_crypto( env: &Env, ctx: Rc, ) -> Result { - let env_clone = env.clone(); let ctx_clone = ctx.clone(); fn inner(expr: &Expr, env: &Env, ctx: Rc) -> Result { let cost_accum = CostAccumulator::new(0, None); diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index b0b23e71f..d67cc304a 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -30,7 +30,7 @@ impl Evaluable for Expr { Expr::Apply(op) => op.eval(env, ctx), Expr::FuncValue(op) => op.eval(env, ctx), Expr::ValUse(op) => op.eval(env, ctx), - Expr::BlockValue(op) => op.eval(env, ctx), + Expr::BlockValue(op) => op.expr().eval(env, ctx), Expr::SelectField(op) => op.eval(env, ctx), Expr::ExtractAmount(op) => op.eval(env, ctx), Expr::ConstPlaceholder(_) => Err(EvalError::UnexpectedExpr( diff --git a/ergotree-ir/src/mir/block.rs b/ergotree-ir/src/mir/block.rs index e7870f8a6..186771970 100644 --- a/ergotree-ir/src/mir/block.rs +++ b/ergotree-ir/src/mir/block.rs @@ -87,7 +87,7 @@ pub mod tests { #[test] fn ser_roundtrip(block in any::()) { - let e = Expr::BlockValue(block); + let e = Expr::BlockValue(block.into()); prop_assert_eq![sigma_serialize_roundtrip(&e), e]; } } diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index f59b0cbb1..dbff018e9 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -122,7 +122,7 @@ pub enum Expr { /// Property call ProperyCall(PropertyCall), /// Block (statements, followed by an expression) - BlockValue(BlockValue), + BlockValue(Spanned), /// let-bound expression ValDef(ValDef), /// Reference to ValDef @@ -245,7 +245,7 @@ impl Expr { Expr::Apply(v) => v.tpe(), Expr::MethodCall(v) => v.tpe(), Expr::ProperyCall(v) => v.tpe(), - Expr::BlockValue(v) => v.tpe(), + Expr::BlockValue(v) => v.expr().tpe(), Expr::ValDef(v) => v.tpe(), Expr::ValUse(v) => v.tpe.clone(), Expr::BinOp(v) => v.tpe(), diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index cc68e5411..45cd3dab9 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -4,6 +4,7 @@ use std::fmt::Write; use thiserror::Error; +use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::expr::Expr; use crate::source_span::Span; @@ -23,31 +24,50 @@ pub trait Print { fn print(&self, w: &mut dyn Printer) -> Result; } +impl Print for BlockValue { + fn print(&self, w: &mut dyn Printer) -> Result { + let start = w.current_pos(); + writeln!(w, "{{")?; + w.inc_ident(); + for item in &self.items { + item.print(w)?; + writeln!(w)?; + } + self.result.print(w)?; + w.dec_ident(); + write!(w, "\n}}")?; + let end = w.current_pos(); + Ok(Spanned { + source_span: Span { start, end }, + expr: self.clone(), + } + .into()) + } +} + impl Print for Append { fn print(&self, w: &mut dyn Printer) -> Result { - let start_pos = w.current_pos(); + let start = w.current_pos(); self.input.print(w)?; write!(w, ".append(")?; self.col_2.print(w)?; write!(w, ")")?; - let end_pos = w.current_pos(); + let end = w.current_pos(); Ok(Spanned { - source_span: Span { - start: start_pos, - end: end_pos, - }, + source_span: Span { start, end }, expr: self.clone(), } .into()) } } -#[allow(clippy::todo)] +#[allow(clippy::panic)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { match self { - Expr::Append(a) => a.expr().print(w), - _ => todo!(), + Expr::Append(v) => v.expr().print(w), + Expr::BlockValue(v) => v.expr().print(w), + e => panic!("Not implemented: {:?}", e), } } } @@ -141,7 +161,6 @@ mod tests { use super::*; fn check(expr: Expr, expected_tree: expect_test::Expect) { - // TODO: create a formatter and grab it's output let print_buf = String::new(); let mut w = PosTrackingWriter { print_buf, @@ -153,23 +172,25 @@ mod tests { } #[test] - fn smoke() { + fn print_block() { let val_id = 2.into(); - let body = Expr::BlockValue(BlockValue { - items: vec![ValDef { - id: val_id, - rhs: Box::new(Expr::Const(1i32.into())), - } - .into()], - result: Box::new( - ValUse { - val_id, - tpe: SType::SInt, + let expr = Expr::BlockValue( + BlockValue { + items: vec![ValDef { + id: val_id, + rhs: Box::new(Expr::Const(1i32.into())), } - .into(), - ), - }); - let expr = Expr::Const(1i32.into()); + .into()], + result: Box::new( + ValUse { + val_id, + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ); check( expr, expect![[r#" diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index d9fe3355b..ed54858a4 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -146,7 +146,7 @@ impl Expr { OpCode::BIT_OR => Ok(bin_op_sigma_parse(BitOp::BitOr.into(), r)?), OpCode::BIT_AND => Ok(bin_op_sigma_parse(BitOp::BitAnd.into(), r)?), OpCode::BIT_XOR => Ok(bin_op_sigma_parse(BitOp::BitXor.into(), r)?), - OpCode::BLOCK_VALUE => Ok(Expr::BlockValue(BlockValue::sigma_parse(r)?)), + OpCode::BLOCK_VALUE => Ok(Expr::BlockValue(BlockValue::sigma_parse(r)?.into())), OpCode::FUNC_VALUE => Ok(Expr::FuncValue(FuncValue::sigma_parse(r)?)), OpCode::APPLY => Ok(Expr::Apply(Apply::sigma_parse(r)?)), OpCode::VAL_DEF => Ok(Expr::ValDef(ValDef::sigma_parse(r)?)), @@ -240,7 +240,7 @@ impl SigmaSerializable for Expr { op.op_code().sigma_serialize(w)?; bin_op_sigma_serialize(op, w) } - Expr::BlockValue(op) => op.sigma_serialize_w_opcode(w), + Expr::BlockValue(op) => op.expr().sigma_serialize_w_opcode(w), Expr::ValUse(op) => op.sigma_serialize_w_opcode(w), Expr::ValDef(op) => op.sigma_serialize_w_opcode(w), Expr::FuncValue(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 94abe8a37..2e8c05d9c 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,5 +1,6 @@ //! Source position for an IR node in the source code +use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::expr::Expr; @@ -35,16 +36,22 @@ impl Spanned { } } -// TODO: can be a macros -impl From for Expr { - fn from(v: Append) -> Self { - Expr::Append(Spanned { - source_span: Span::empty(), - expr: v, - }) - } +macro_rules! into_expr { + ($variant: ident) => { + impl From<$variant> for Expr { + fn from(v: $variant) -> Self { + Expr::$variant(Spanned { + source_span: Span::empty(), + expr: v, + }) + } + } + }; } +into_expr!(Append); +into_expr!(BlockValue); + impl From for Spanned { fn from(v: T) -> Self { Spanned { From c10d084b2e7f742ba28b124bfc9628928e3915ad Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 4 Aug 2023 11:22:27 +0300 Subject: [PATCH 15/74] formatting; --- ergotree-ir/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ergotree-ir/src/lib.rs b/ergotree-ir/src/lib.rs index 1bc1c274a..b30bff3ae 100644 --- a/ergotree-ir/src/lib.rs +++ b/ergotree-ir/src/lib.rs @@ -26,10 +26,10 @@ pub mod bigint256; pub mod chain; pub mod ergo_tree; pub mod mir; +pub mod pretty_printer; pub mod serialization; pub mod sigma_protocol; pub mod source_span; pub mod type_check; pub mod types; pub mod util; -pub mod pretty_printer; From 0eb274b355ae951e456b53fc93e01caa5be2c11d Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 7 Aug 2023 09:23:31 +0300 Subject: [PATCH 16/74] impl Print for ValDef and Constant; --- ergotree-interpreter/src/eval/apply.rs | 2 +- ergotree-interpreter/src/eval/block.rs | 7 ++++-- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/mir/val_def.rs | 2 +- ergotree-ir/src/pretty_printer.rs | 30 +++++++++++++++++++++++++- ergotree-ir/src/serialization/expr.rs | 4 ++-- ergotree-ir/src/source_span.rs | 2 ++ 7 files changed, 42 insertions(+), 9 deletions(-) diff --git a/ergotree-interpreter/src/eval/apply.rs b/ergotree-interpreter/src/eval/apply.rs index 073e0f1fd..e4a6c3407 100644 --- a/ergotree-interpreter/src/eval/apply.rs +++ b/ergotree-interpreter/src/eval/apply.rs @@ -77,7 +77,7 @@ mod tests { } .into()], result: Box::new(bin_op), - }); + }.into()); let apply: Expr = Apply::new( FuncValue::new( vec![FuncArg { diff --git a/ergotree-interpreter/src/eval/block.rs b/ergotree-interpreter/src/eval/block.rs index fc73b5be2..dfe5b3c21 100644 --- a/ergotree-interpreter/src/eval/block.rs +++ b/ergotree-interpreter/src/eval/block.rs @@ -2,6 +2,7 @@ use ergotree_ir::mir::block::BlockValue; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::val_def::ValDef; use ergotree_ir::mir::value::Value; +use ergotree_ir::source_span::Spanned; use crate::eval::env::Env; use crate::eval::EvalContext; @@ -11,7 +12,9 @@ use crate::eval::Evaluable; impl Evaluable for BlockValue { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { for i in &self.items { - let val_def = i.clone().try_extract_into::()?; + // TODO: new try_extract_spanned_into? + let spanned_val_def = &i.clone().try_extract_into::>()?; + let val_def = spanned_val_def.expr(); let v: Value = val_def.rhs.eval(env, ctx)?; env.insert(val_def.id, v); } @@ -31,7 +34,7 @@ mod tests { #[test] fn ser_roundtrip(block in any::()) { - let e = Expr::BlockValue(block); + let e = Expr::BlockValue(block.into()); prop_assert_eq![sigma_serialize_roundtrip(&e), e]; } } diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index dbff018e9..a00d621ef 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -124,7 +124,7 @@ pub enum Expr { /// Block (statements, followed by an expression) BlockValue(Spanned), /// let-bound expression - ValDef(ValDef), + ValDef(Spanned), /// Reference to ValDef ValUse(ValUse), /// If, non-lazy - evaluate both branches @@ -246,7 +246,7 @@ impl Expr { Expr::MethodCall(v) => v.tpe(), Expr::ProperyCall(v) => v.tpe(), Expr::BlockValue(v) => v.expr().tpe(), - Expr::ValDef(v) => v.tpe(), + Expr::ValDef(v) => v.expr().tpe(), Expr::ValUse(v) => v.tpe.clone(), Expr::BinOp(v) => v.tpe(), Expr::OptionGet(v) => v.tpe(), diff --git a/ergotree-ir/src/mir/val_def.rs b/ergotree-ir/src/mir/val_def.rs index d213359f5..b2f5c0580 100644 --- a/ergotree-ir/src/mir/val_def.rs +++ b/ergotree-ir/src/mir/val_def.rs @@ -87,7 +87,7 @@ mod tests { #[test] fn ser_roundtrip(v in any::()) { - let e = Expr::ValDef(v); + let e = Expr::ValDef(v.into()); prop_assert_eq![sigma_serialize_roundtrip(&e), e]; } } diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 45cd3dab9..a21cd3c51 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -6,7 +6,9 @@ use thiserror::Error; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; +use crate::mir::constant::Constant; use crate::mir::expr::Expr; +use crate::mir::val_def::ValDef; use crate::source_span::Span; use crate::source_span::Spanned; @@ -45,6 +47,29 @@ impl Print for BlockValue { } } +impl Print for ValDef { + fn print(&self, w: &mut dyn Printer) -> Result { + let start = w.current_pos(); + write!(w, "val v{} = ", self.id)?; + self.rhs.print(w)?; + let end = w.current_pos(); + writeln!(w)?; + Ok(Spanned { + source_span: Span { start, end }, + expr: self.clone(), + } + .into()) + } +} + +impl Print for Constant { + fn print(&self, w: &mut dyn Printer) -> Result { + // TODO: implement Display for Literal + write!(w, "{:?}", self.v)?; + Ok(self.clone().into()) + } +} + impl Print for Append { fn print(&self, w: &mut dyn Printer) -> Result { let start = w.current_pos(); @@ -67,6 +92,8 @@ impl Print for Expr { match self { Expr::Append(v) => v.expr().print(w), Expr::BlockValue(v) => v.expr().print(w), + Expr::ValDef(v) => v.expr().print(w), + Expr::Const(v) => v.print(w), e => panic!("Not implemented: {:?}", e), } } @@ -167,8 +194,9 @@ mod tests { current_pos: 0, current_indent: 0, }; - let spanned_expr = expr.print(&mut w).unwrap(); + let _ = expr.print(&mut w).unwrap(); expected_tree.assert_eq(w.get_buf()); + // todo!("check source spans"); } #[test] diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index ed54858a4..e3d64289e 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -149,7 +149,7 @@ impl Expr { OpCode::BLOCK_VALUE => Ok(Expr::BlockValue(BlockValue::sigma_parse(r)?.into())), OpCode::FUNC_VALUE => Ok(Expr::FuncValue(FuncValue::sigma_parse(r)?)), OpCode::APPLY => Ok(Expr::Apply(Apply::sigma_parse(r)?)), - OpCode::VAL_DEF => Ok(Expr::ValDef(ValDef::sigma_parse(r)?)), + OpCode::VAL_DEF => Ok(Expr::ValDef(ValDef::sigma_parse(r)?.into())), OpCode::VAL_USE => Ok(Expr::ValUse(ValUse::sigma_parse(r)?)), ExtractAmount::OP_CODE => Ok(Expr::ExtractAmount(ExtractAmount::sigma_parse(r)?)), OpCode::SELECT_FIELD => Ok(Expr::SelectField(SelectField::sigma_parse(r)?)), @@ -242,7 +242,7 @@ impl SigmaSerializable for Expr { } Expr::BlockValue(op) => op.expr().sigma_serialize_w_opcode(w), Expr::ValUse(op) => op.sigma_serialize_w_opcode(w), - Expr::ValDef(op) => op.sigma_serialize_w_opcode(w), + Expr::ValDef(op) => op.expr().sigma_serialize_w_opcode(w), Expr::FuncValue(op) => op.sigma_serialize_w_opcode(w), Expr::Apply(op) => op.sigma_serialize_w_opcode(w), Expr::ExtractAmount(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 2e8c05d9c..2c3904289 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,5 +1,6 @@ //! Source position for an IR node in the source code +use crate::mir::val_def::ValDef; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::expr::Expr; @@ -51,6 +52,7 @@ macro_rules! into_expr { into_expr!(Append); into_expr!(BlockValue); +into_expr!(ValDef); impl From for Spanned { fn from(v: T) -> Self { From 8bb11819365ea1dd23569330f78b70190d30e55e Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 7 Aug 2023 09:44:42 +0300 Subject: [PATCH 17/74] impl Print for ValUse, fix indentations and new lines in pretty printer; --- ergotree-ir/src/pretty_printer.rs | 37 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index a21cd3c51..4ed95b5f5 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -9,6 +9,7 @@ use crate::mir::coll_append::Append; use crate::mir::constant::Constant; use crate::mir::expr::Expr; use crate::mir::val_def::ValDef; +use crate::mir::val_use::ValUse; use crate::source_span::Span; use crate::source_span::Spanned; @@ -31,13 +32,17 @@ impl Print for BlockValue { let start = w.current_pos(); writeln!(w, "{{")?; w.inc_ident(); + let indent = w.get_indent(); for item in &self.items { + write!(w, "{:indent$}", "", indent = indent)?; item.print(w)?; writeln!(w)?; } + // indent for result + write!(w, "{:indent$}", "", indent = indent)?; self.result.print(w)?; w.dec_ident(); - write!(w, "\n}}")?; + writeln!(w, "\n}}")?; let end = w.current_pos(); Ok(Spanned { source_span: Span { start, end }, @@ -53,7 +58,6 @@ impl Print for ValDef { write!(w, "val v{} = ", self.id)?; self.rhs.print(w)?; let end = w.current_pos(); - writeln!(w)?; Ok(Spanned { source_span: Span { start, end }, expr: self.clone(), @@ -70,6 +74,13 @@ impl Print for Constant { } } +impl Print for ValUse { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "v{}", self.val_id)?; + Ok(self.clone().into()) + } +} + impl Print for Append { fn print(&self, w: &mut dyn Printer) -> Result { let start = w.current_pos(); @@ -93,6 +104,7 @@ impl Print for Expr { Expr::Append(v) => v.expr().print(w), Expr::BlockValue(v) => v.expr().print(w), Expr::ValDef(v) => v.expr().print(w), + Expr::ValUse(v) => v.print(w), Expr::Const(v) => v.print(w), e => panic!("Not implemented: {:?}", e), } @@ -108,6 +120,8 @@ pub trait Printer: Write { fn inc_ident(&mut self); /// Decrease indent fn dec_ident(&mut self); + /// Get current indent + fn get_indent(&self) -> usize; } /// Printer implementation with tracking of current position and indent @@ -119,20 +133,9 @@ pub struct PosTrackingWriter { impl Write for PosTrackingWriter { fn write_str(&mut self, s: &str) -> std::fmt::Result { - let indented_str = s - .lines() - .map(|l| { - let mut indent = String::new(); - for _ in 0..self.current_indent { - indent.push(' '); - } - format!("{}{}", indent, l) - }) - .collect::>() - .join("\n"); let len = s.len(); self.current_pos += len; - write!(self.print_buf, "{}", indented_str) + write!(self.print_buf, "{}", s) } } @@ -148,6 +151,10 @@ impl Printer for PosTrackingWriter { fn dec_ident(&mut self) { self.current_indent -= Self::INDENT; } + + fn get_indent(&self) -> usize { + self.current_indent + } } impl PosTrackingWriter { @@ -201,7 +208,7 @@ mod tests { #[test] fn print_block() { - let val_id = 2.into(); + let val_id = 1.into(); let expr = Expr::BlockValue( BlockValue { items: vec![ValDef { From c6b94db084c45869bee7d336de854283f9299a6a Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 8 Aug 2023 10:21:55 +0300 Subject: [PATCH 18/74] Rename Span to SourceSpan and switch it to offset+length based representation; --- ergotree-interpreter/src/eval/error.rs | 12 +++++------ ergotree-ir/src/pretty_printer.rs | 20 +++++++++--------- ergotree-ir/src/source_span.rs | 28 +++++++++++++++----------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 8bda2d865..b325a4c6e 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -3,7 +3,7 @@ use ergotree_ir::ergo_tree::ErgoTreeError; use ergotree_ir::mir::constant::TryExtractFromError; use ergotree_ir::serialization::SigmaParsingError; use ergotree_ir::serialization::SigmaSerializationError; -use ergotree_ir::source_span::Span; +use ergotree_ir::source_span::SourceSpan; use sigma_ser::ScorexParsingError; use sigma_ser::ScorexSerializationError; use thiserror::Error; @@ -78,7 +78,7 @@ pub enum EvalError { #[derive(PartialEq, Eq, Debug, Clone)] pub struct EvalErrorDetails { /// source span - source_span: Span, + source_span: SourceSpan, /// environment after evaluation env: Env, /// source code @@ -87,7 +87,7 @@ pub struct EvalErrorDetails { impl EvalError { /// Wrap eval error with source span - pub fn wrap(self, source_span: Span, env: Env) -> Self { + pub fn wrap(self, source_span: SourceSpan, env: Env) -> Self { EvalError::Wrapped { error: Box::new(self), details: EvalErrorDetails { @@ -112,7 +112,7 @@ impl EvalError { e => EvalError::Wrapped { error: Box::new(e), details: EvalErrorDetails { - source_span: Span::empty(), + source_span: SourceSpan::empty(), env: Env::empty(), source: Some(source), }, @@ -122,11 +122,11 @@ impl EvalError { } pub trait ExtResultEvalError { - fn enrich_err(self, span: Span, env: Env) -> Result; + fn enrich_err(self, span: SourceSpan, env: Env) -> Result; } impl ExtResultEvalError for Result { - fn enrich_err(self, span: Span, env: Env) -> Result { + fn enrich_err(self, span: SourceSpan, env: Env) -> Result { self.map_err(|e| e.wrap(span, env)) } } diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 4ed95b5f5..97ec14795 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -10,7 +10,7 @@ use crate::mir::constant::Constant; use crate::mir::expr::Expr; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; -use crate::source_span::Span; +use crate::source_span::SourceSpan; use crate::source_span::Spanned; /// Print error @@ -29,7 +29,7 @@ pub trait Print { impl Print for BlockValue { fn print(&self, w: &mut dyn Printer) -> Result { - let start = w.current_pos(); + let offset = w.current_pos(); writeln!(w, "{{")?; w.inc_ident(); let indent = w.get_indent(); @@ -43,9 +43,9 @@ impl Print for BlockValue { self.result.print(w)?; w.dec_ident(); writeln!(w, "\n}}")?; - let end = w.current_pos(); + let length = w.current_pos() - offset; Ok(Spanned { - source_span: Span { start, end }, + source_span: SourceSpan { offset, length }, expr: self.clone(), } .into()) @@ -54,12 +54,12 @@ impl Print for BlockValue { impl Print for ValDef { fn print(&self, w: &mut dyn Printer) -> Result { - let start = w.current_pos(); + let offset = w.current_pos(); write!(w, "val v{} = ", self.id)?; self.rhs.print(w)?; - let end = w.current_pos(); + let length = w.current_pos() - offset; Ok(Spanned { - source_span: Span { start, end }, + source_span: SourceSpan { offset, length }, expr: self.clone(), } .into()) @@ -83,14 +83,14 @@ impl Print for ValUse { impl Print for Append { fn print(&self, w: &mut dyn Printer) -> Result { - let start = w.current_pos(); + let offset = w.current_pos(); self.input.print(w)?; write!(w, ".append(")?; self.col_2.print(w)?; write!(w, ")")?; - let end = w.current_pos(); + let length = w.current_pos() - offset; Ok(Spanned { - source_span: Span { start, end }, + source_span: SourceSpan { offset, length }, expr: self.clone(), } .into()) diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 2c3904289..6388cf22d 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,31 +1,35 @@ //! Source position for an IR node in the source code -use crate::mir::val_def::ValDef; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::expr::Expr; +use crate::mir::val_def::ValDef; /// Source position for the Expr #[derive(PartialEq, Eq, Debug, Clone)] -pub struct Span { - /// Start position in the source code - pub start: usize, - /// End position in the source code - pub end: usize, +pub struct SourceSpan { + /// Start position in the span + pub offset: usize, + /// The length of the span + pub length: usize, } -impl Span { +impl SourceSpan { /// Empty span pub fn empty() -> Self { - Span { start: 0, end: 0 } + SourceSpan { + offset: 0, + length: 0, + } } } + /// Wrapper for Expr with source position #[derive(PartialEq, Eq, Debug, Clone)] pub struct Spanned { /// Source position - pub source_span: Span, + pub source_span: SourceSpan, /// Wrapped value pub expr: T, } @@ -42,7 +46,7 @@ macro_rules! into_expr { impl From<$variant> for Expr { fn from(v: $variant) -> Self { Expr::$variant(Spanned { - source_span: Span::empty(), + source_span: SourceSpan::empty(), expr: v, }) } @@ -57,7 +61,7 @@ into_expr!(ValDef); impl From for Spanned { fn from(v: T) -> Self { Spanned { - source_span: Span::empty(), + source_span: SourceSpan::empty(), expr: v, } } @@ -66,7 +70,7 @@ impl From for Spanned { impl Expr { /// Source span for the Expr #[allow(clippy::todo)] - pub fn span(&self) -> &Span { + pub fn span(&self) -> &SourceSpan { match self { Expr::Append(op) => &op.source_span, Expr::Const(_) => todo!(), From be311acbb9f6e11a1013b7daac44839f91673f5e Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 8 Aug 2023 11:59:59 +0300 Subject: [PATCH 19/74] impl Print for BinOp; --- ergotree-interpreter/src/eval/apply.rs | 52 +++++++----- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-interpreter/src/eval/subst_const.rs | 24 ++++-- ergotree-ir/src/chain/address.rs | 24 ++++-- ergotree-ir/src/mir/bin_op.rs | 89 +++++++++++++++++--- ergotree-ir/src/mir/expr.rs | 4 +- ergotree-ir/src/pretty_printer.rs | 58 ++++++++++++- ergotree-ir/src/serialization/expr.rs | 4 +- ergotree-ir/src/source_span.rs | 3 +- ergotree-ir/src/type_check.rs | 6 +- 10 files changed, 206 insertions(+), 60 deletions(-) diff --git a/ergotree-interpreter/src/eval/apply.rs b/ergotree-interpreter/src/eval/apply.rs index e4a6c3407..9a3c93352 100644 --- a/ergotree-interpreter/src/eval/apply.rs +++ b/ergotree-interpreter/src/eval/apply.rs @@ -53,31 +53,37 @@ mod tests { #[test] fn eval_user_defined_func_call() { let arg = Expr::Const(1i32.into()); - let bin_op = Expr::BinOp(BinOp { - kind: RelationOp::Eq.into(), - left: Box::new( - ValUse { - val_id: 1.into(), - tpe: SType::SInt, - } - .into(), - ), - right: Box::new( - ValUse { - val_id: 2.into(), - tpe: SType::SInt, + let bin_op = Expr::BinOp( + BinOp { + kind: RelationOp::Eq.into(), + left: Box::new( + ValUse { + val_id: 1.into(), + tpe: SType::SInt, + } + .into(), + ), + right: Box::new( + ValUse { + val_id: 2.into(), + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ); + let body = Expr::BlockValue( + BlockValue { + items: vec![ValDef { + id: 2.into(), + rhs: Box::new(Expr::Const(1i32.into())), } - .into(), - ), - }); - let body = Expr::BlockValue(BlockValue { - items: vec![ValDef { - id: 2.into(), - rhs: Box::new(Expr::Const(1i32.into())), + .into()], + result: Box::new(bin_op), } - .into()], - result: Box::new(bin_op), - }.into()); + .into(), + ); let apply: Expr = Apply::new( FuncValue::new( vec![FuncArg { diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index d67cc304a..4187fc59a 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -23,7 +23,7 @@ impl Evaluable for Expr { Expr::GlobalVars(op) => op.eval(env, ctx), Expr::MethodCall(op) => op.eval(env, ctx), Expr::ProperyCall(op) => op.eval(env, ctx), - Expr::BinOp(op) => op.eval(env, ctx), + Expr::BinOp(op) => op.expr().eval(env, ctx), Expr::Global => Ok(Value::Global), Expr::Context => Ok(Value::Context), Expr::OptionGet(v) => v.eval(env, ctx), diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs index 97825336c..f70b2a1d9 100644 --- a/ergotree-interpreter/src/eval/subst_const.rs +++ b/ergotree-interpreter/src/eval/subst_const.rs @@ -150,15 +150,21 @@ mod tests { fn test_3_substitutions(original: (i32, i32, i32), new: (i32, i32, i32)) { let (o0, o1, o2) = original; let (n0, n1, n2) = new; - let expr = Expr::BinOp(BinOp { - kind: BinOpKind::Arith(ArithOp::Plus), - left: Box::new(Expr::Const(o0.into())), - right: Box::new(Expr::BinOp(BinOp { - kind: BinOpKind::Arith(ArithOp::Multiply), - left: Box::new(Expr::Const(o1.into())), - right: Box::new(Expr::Const(o2.into())), - })), - }); + let expr = Expr::BinOp( + BinOp { + kind: BinOpKind::Arith(ArithOp::Plus), + left: Box::new(Expr::Const(o0.into())), + right: Box::new(Expr::BinOp( + BinOp { + kind: BinOpKind::Arith(ArithOp::Multiply), + left: Box::new(Expr::Const(o1.into())), + right: Box::new(Expr::Const(o2.into())), + } + .into(), + )), + } + .into(), + ); let ergo_tree = ErgoTree::new(ErgoTreeHeader::v0(true), &expr).unwrap(); assert_eq!(ergo_tree.constants_len().unwrap(), 3); assert_eq!(ergo_tree.get_constant(0).unwrap().unwrap(), o0.into()); diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index ebd2dcdb2..8fc6c3e4b 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -22,6 +22,7 @@ use crate::sigma_protocol::sigma_boolean::ProveDlog; use crate::sigma_protocol::sigma_boolean::SigmaBoolean; use crate::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree; use crate::sigma_protocol::sigma_boolean::SigmaProp; +use crate::source_span::Spanned; use crate::types::stype::SType; use ergo_chain_types::EcPoint; @@ -110,8 +111,14 @@ impl Address { if let [Expr::BoolToSigmaProp(BoolToSigmaProp { input }), Expr::DeserializeContext(DeserializeContext { tpe, id })] = items.as_slice() { - if let (Expr::BinOp(BinOp { kind, left, right }), SType::SSigmaProp, 1) = - (*input.clone(), tpe.clone(), id) + if let ( + Expr::BinOp(Spanned { + source_span: _, + expr: BinOp { kind, left, right }, + }), + SType::SSigmaProp, + 1, + ) = (*input.clone(), tpe.clone(), id) { if let ( Relation(RelationOp::Eq), @@ -212,11 +219,14 @@ impl Address { from: Box::new(0i32.into()), until: Box::new(24i32.into()), }); - let hash_equals = Expr::BinOp(BinOp { - kind: Relation(RelationOp::Eq), - left: Box::new(slice_expr), - right: Box::new(Expr::Const(Constant::from(script_hash.to_vec()))), - }); + let hash_equals = Expr::BinOp( + BinOp { + kind: Relation(RelationOp::Eq), + left: Box::new(slice_expr), + right: Box::new(Expr::Const(Constant::from(script_hash.to_vec()))), + } + .into(), + ); let script_is_correct = Expr::DeserializeContext(DeserializeContext { tpe: SType::SSigmaProp, id: 1, diff --git a/ergotree-ir/src/mir/bin_op.rs b/ergotree-ir/src/mir/bin_op.rs index 102cf9b25..cc82e4d8c 100644 --- a/ergotree-ir/src/mir/bin_op.rs +++ b/ergotree-ir/src/mir/bin_op.rs @@ -1,5 +1,7 @@ //! Operators in ErgoTree +use std::fmt::Display; + use super::expr::Expr; use crate::has_opcode::HasOpCode; use crate::serialization::op_code::OpCode; @@ -45,6 +47,20 @@ impl From for OpCode { } } +impl Display for ArithOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ArithOp::Plus => write!(f, "+"), + ArithOp::Minus => write!(f, "-"), + ArithOp::Multiply => write!(f, "*"), + ArithOp::Divide => write!(f, "/"), + ArithOp::Max => write!(f, "max"), + ArithOp::Min => write!(f, "min"), + ArithOp::Modulo => write!(f, "%"), + } + } +} + /// Relational operations #[derive(PartialEq, Eq, Debug, Clone, Copy)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -76,6 +92,19 @@ impl From for OpCode { } } +impl Display for RelationOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RelationOp::Eq => write!(f, "=="), + RelationOp::NEq => write!(f, "!="), + RelationOp::Ge => write!(f, ">="), + RelationOp::Gt => write!(f, ">"), + RelationOp::Le => write!(f, "<="), + RelationOp::Lt => write!(f, "<"), + } + } +} + /// Logical operations #[derive(PartialEq, Eq, Debug, Clone, Copy)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -98,6 +127,16 @@ impl From for OpCode { } } +impl Display for LogicalOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + LogicalOp::And => write!(f, "&&"), + LogicalOp::Or => write!(f, "||"), + LogicalOp::Xor => write!(f, "^"), + } + } +} + /// Bitwise operations #[derive(PartialEq, Eq, Debug, Clone, Copy)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -120,6 +159,16 @@ impl From for OpCode { } } +impl Display for BitOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BitOp::BitOr => write!(f, "|"), + BitOp::BitAnd => write!(f, "&"), + BitOp::BitXor => write!(f, "^"), + } + } +} + /// Binary operations #[derive(PartialEq, Eq, Debug, Clone, Copy, From)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -145,6 +194,17 @@ impl From for OpCode { } } +impl Display for BinOpKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BinOpKind::Arith(op) => write!(f, "{}", op), + BinOpKind::Relation(op) => write!(f, "{}", op), + BinOpKind::Logical(op) => write!(f, "{}", op), + BinOpKind::Bit(op) => write!(f, "{}", op), + } + } +} + /// Binary operation #[derive(PartialEq, Eq, Debug, Clone)] pub struct BinOp { @@ -292,19 +352,22 @@ mod tests { let e = Expr::sigma_parse_bytes(&[0xed, 0x85, 0x03]); assert_eq!( e, - Ok(Expr::BinOp(BinOp { - kind: BinOpKind::Logical(LogicalOp::And,), - left: Expr::Const(Constant { - tpe: SType::SBoolean, - v: Boolean(true), - }) - .into(), - right: Expr::Const(Constant { - tpe: SType::SBoolean, - v: Boolean(true), - }) - .into(), - })) + Ok(Expr::BinOp( + BinOp { + kind: BinOpKind::Logical(LogicalOp::And,), + left: Expr::Const(Constant { + tpe: SType::SBoolean, + v: Boolean(true), + }) + .into(), + right: Expr::Const(Constant { + tpe: SType::SBoolean, + v: Boolean(true), + }) + .into(), + } + .into() + )) ); } } diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index a00d621ef..bfcc6c87d 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -130,7 +130,7 @@ pub enum Expr { /// If, non-lazy - evaluate both branches If(If), /// Binary operation - BinOp(BinOp), + BinOp(Spanned), /// Logical AND And(And), /// Logical OR @@ -248,7 +248,7 @@ impl Expr { Expr::BlockValue(v) => v.expr().tpe(), Expr::ValDef(v) => v.expr().tpe(), Expr::ValUse(v) => v.tpe.clone(), - Expr::BinOp(v) => v.tpe(), + Expr::BinOp(v) => v.expr().tpe(), Expr::OptionGet(v) => v.tpe(), Expr::ExtractRegisterAs(v) => v.tpe(), Expr::Fold(v) => v.tpe(), diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 97ec14795..adcb810fc 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -4,6 +4,7 @@ use std::fmt::Write; use thiserror::Error; +use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::constant::Constant; @@ -97,6 +98,21 @@ impl Print for Append { } } +impl Print for BinOp { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + self.left.print(w)?; + write!(w, " {} ", self.kind)?; + self.right.print(w)?; + let length = w.current_pos() - offset; + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: self.clone(), + } + .into()) + } +} + #[allow(clippy::panic)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { @@ -106,6 +122,7 @@ impl Print for Expr { Expr::ValDef(v) => v.expr().print(w), Expr::ValUse(v) => v.print(w), Expr::Const(v) => v.print(w), + Expr::BinOp(v) => v.expr().print(w), e => panic!("Not implemented: {:?}", e), } } @@ -187,6 +204,8 @@ mod tests { use expect_test::expect; + use crate::mir::bin_op::ArithOp; + use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; @@ -203,7 +222,6 @@ mod tests { }; let _ = expr.print(&mut w).unwrap(); expected_tree.assert_eq(w.get_buf()); - // todo!("check source spans"); } #[test] @@ -236,4 +254,42 @@ mod tests { "#]], ); } + + #[test] + fn print_binop() { + let val_id = 1.into(); + let expr = Expr::BlockValue( + BlockValue { + items: vec![ValDef { + id: val_id, + rhs: Box::new( + BinOp { + kind: ArithOp::Divide.into(), + left: Expr::Const(4i32.into()).into(), + right: Expr::Const(2i32.into()).into(), + } + .into(), + ), + } + .into()], + result: Box::new( + ValUse { + val_id, + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ); + check( + expr, + expect![[r#" + { + val v1 = 4 / 2 + v1 + } + "#]], + ); + } } diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index e3d64289e..bf25c0bcf 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -237,8 +237,8 @@ impl SigmaSerializable for Expr { Expr::OptionGet(v) => v.sigma_serialize_w_opcode(w), Expr::ExtractRegisterAs(v) => v.sigma_serialize_w_opcode(w), Expr::BinOp(op) => { - op.op_code().sigma_serialize(w)?; - bin_op_sigma_serialize(op, w) + op.expr().op_code().sigma_serialize(w)?; + bin_op_sigma_serialize(op.expr(), w) } Expr::BlockValue(op) => op.expr().sigma_serialize_w_opcode(w), Expr::ValUse(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 6388cf22d..e71d08156 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,5 +1,6 @@ //! Source position for an IR node in the source code +use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::expr::Expr; @@ -24,7 +25,6 @@ impl SourceSpan { } } - /// Wrapper for Expr with source position #[derive(PartialEq, Eq, Debug, Clone)] pub struct Spanned { @@ -57,6 +57,7 @@ macro_rules! into_expr { into_expr!(Append); into_expr!(BlockValue); into_expr!(ValDef); +into_expr!(BinOp); impl From for Spanned { fn from(v: T) -> Self { diff --git a/ergotree-ir/src/type_check.rs b/ergotree-ir/src/type_check.rs index 53b8bf457..447db8593 100644 --- a/ergotree-ir/src/type_check.rs +++ b/ergotree-ir/src/type_check.rs @@ -1,6 +1,7 @@ //! Type checking use crate::mir::expr::Expr; +use crate::source_span::Spanned; /// Typecheck error #[derive(Debug, PartialEq, Eq)] @@ -24,7 +25,10 @@ impl TypeCheckError { pub fn type_check(e: Expr) -> Result { // not really a relevant check, since such kind of check should be in BinOp::new() match &e { - Expr::BinOp(bin) => { + Expr::BinOp(Spanned { + source_span: _, + expr: bin, + }) => { if bin.left.tpe() == bin.right.tpe() { Ok(e) } else { From a94826630e5e1f4d2ab5b19f16241c002f3dc316 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 8 Aug 2023 12:41:59 +0300 Subject: [PATCH 20/74] fix nested error wrapping, add division by zero eval test; --- ergotree-interpreter/Cargo.toml | 18 +++--- ergotree-interpreter/src/eval/error.rs | 76 +++++++++++++++++++++++++- ergotree-interpreter/src/eval/expr.rs | 4 +- ergotree-ir/src/source_span.rs | 16 +++--- 4 files changed, 97 insertions(+), 17 deletions(-) diff --git a/ergotree-interpreter/Cargo.toml b/ergotree-interpreter/Cargo.toml index ce6934ac2..9ed5d5336 100644 --- a/ergotree-interpreter/Cargo.toml +++ b/ergotree-interpreter/Cargo.toml @@ -6,9 +6,7 @@ authors = ["Denys Zadorozhnyi "] repository.workspace = true edition.workspace = true description = "ErgoTree interpreter" -exclude = [ - "proptest-regressions/*" -] +exclude = ["proptest-regressions/*"] [lib] crate-type = ["cdylib", "rlib"] @@ -31,22 +29,28 @@ base16 = { workspace = true } proptest-derive = { workspace = true, optional = true } bytes = { workspace = true } num-bigint = { workspace = true } -bounded-vec = { workspace = true, features=["serde"] } +bounded-vec = { workspace = true, features = ["serde"] } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } serde_with = { workspace = true, optional = true } -proptest = { workspace = true , optional = true } +proptest = { workspace = true, optional = true } scorex_crypto_avltree = "0.1.0" gf2_192 = { version = "^0.24.1", path = "../gf2_192" } [features] default = ["json"] json = ["serde", "serde_json", "serde_with", "bounded-vec/serde"] -arbitrary = ["proptest", "proptest-derive", "ergotree-ir/arbitrary", "ergo-chain-types/arbitrary", "gf2_192/arbitrary"] +arbitrary = [ + "proptest", + "proptest-derive", + "ergotree-ir/arbitrary", + "ergo-chain-types/arbitrary", + "gf2_192/arbitrary", +] [dev-dependencies] ergotree-ir = { workspace = true, features = ["arbitrary"] } ergoscript-compiler = { workspace = true } proptest = { workspace = true } sigma-test-util = { workspace = true } - +expect-test = { workspace = true } diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index b325a4c6e..1d4d2fc95 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -127,6 +127,80 @@ pub trait ExtResultEvalError { impl ExtResultEvalError for Result { fn enrich_err(self, span: SourceSpan, env: Env) -> Result { - self.map_err(|e| e.wrap(span, env)) + self.map_err(|e| match e { + // skip already wrapped errors + w @ EvalError::Wrapped { + error: _, + details: _, + } => w, + e => e.wrap(span, env), + }) + } +} + +#[allow(clippy::unwrap_used)] +#[cfg(test)] +mod tests { + use std::rc::Rc; + + use expect_test::expect; + + use ergotree_ir::mir::bin_op::ArithOp; + use ergotree_ir::mir::bin_op::BinOp; + use ergotree_ir::mir::block::BlockValue; + use ergotree_ir::mir::expr::Expr; + use ergotree_ir::mir::val_def::ValDef; + use ergotree_ir::mir::val_use::ValUse; + use ergotree_ir::pretty_printer::PosTrackingWriter; + use ergotree_ir::pretty_printer::Print; + use ergotree_ir::types::stype::SType; + use sigma_test_util::force_any_val; + + use crate::eval::context::Context; + use crate::eval::tests::try_eval_out; + + fn check(expr: Expr, expected_tree: expect_test::Expect) { + let mut w = PosTrackingWriter::new(); + let spanned_expr = expr.print(&mut w).unwrap(); + dbg!(&spanned_expr); + let ctx = Rc::new(force_any_val::()); + let err_raw = try_eval_out::(&spanned_expr, ctx).err().unwrap(); + // let err = err_raw.wrap_with_src(w.get_buf().to_string()); + let err_msg = format!("{:?}", err_raw); + expected_tree.assert_eq(&err_msg); + } + + #[test] + fn pretty_binop_div_zero() { + let val_id = 1.into(); + let expr = Expr::BlockValue( + BlockValue { + items: vec![ValDef { + id: val_id, + rhs: Box::new( + BinOp { + kind: ArithOp::Divide.into(), + left: Expr::Const(1i32.into()).into(), + right: Expr::Const(0i32.into()).into(), + } + .into(), + ), + } + .into()], + result: Box::new( + ValUse { + val_id, + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ); + check( + expr, + expect![[r#" + "#]], + ) } } diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 4187fc59a..6e8b6fe98 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -1,3 +1,5 @@ +//! Evaluation of ErgoTree expressions + use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; @@ -82,6 +84,6 @@ impl Evaluable for Expr { Expr::TreeLookup(op) => op.eval(env, ctx), Expr::CreateAvlTree(op) => op.eval(env, ctx), }; - res.enrich_err(self.span().clone(), env.clone()) + res.enrich_err(self.span(), env.clone()) } } diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index e71d08156..10bfe7665 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -7,7 +7,7 @@ use crate::mir::expr::Expr; use crate::mir::val_def::ValDef; /// Source position for the Expr -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone, Copy)] pub struct SourceSpan { /// Start position in the span pub offset: usize, @@ -71,10 +71,10 @@ impl From for Spanned { impl Expr { /// Source span for the Expr #[allow(clippy::todo)] - pub fn span(&self) -> &SourceSpan { + pub fn span(&self) -> SourceSpan { match self { - Expr::Append(op) => &op.source_span, - Expr::Const(_) => todo!(), + Expr::Append(op) => op.source_span, + Expr::Const(_) => SourceSpan::empty(), Expr::ConstPlaceholder(_) => todo!(), Expr::SubstConstants(_) => todo!(), Expr::ByteArrayToLong(_) => todo!(), @@ -91,11 +91,11 @@ impl Expr { Expr::Apply(_) => todo!(), Expr::MethodCall(_) => todo!(), Expr::ProperyCall(_) => todo!(), - Expr::BlockValue(_) => todo!(), - Expr::ValDef(_) => todo!(), - Expr::ValUse(_) => todo!(), + Expr::BlockValue(op) => op.source_span, + Expr::ValDef(op) => op.source_span, + Expr::ValUse(_) => SourceSpan::empty(), Expr::If(_) => todo!(), - Expr::BinOp(_) => todo!(), + Expr::BinOp(op) => op.source_span, Expr::And(_) => todo!(), Expr::Or(_) => todo!(), Expr::Xor(_) => todo!(), From d353c710629da2f7827b13bbf0cd5a47819c8d0e Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 8 Aug 2023 15:35:24 +0300 Subject: [PATCH 21/74] fix spanned Expr construction in Print implementations; --- ergotree-ir/src/pretty_printer.rs | 63 +++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index adcb810fc..f5cc2c386 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -34,20 +34,24 @@ impl Print for BlockValue { writeln!(w, "{{")?; w.inc_ident(); let indent = w.get_indent(); + let mut items = Vec::new(); for item in &self.items { write!(w, "{:indent$}", "", indent = indent)?; - item.print(w)?; + items.push(item.print(w)?); writeln!(w)?; } // indent for result write!(w, "{:indent$}", "", indent = indent)?; - self.result.print(w)?; + let res = self.result.print(w)?; w.dec_ident(); writeln!(w, "\n}}")?; let length = w.current_pos() - offset; Ok(Spanned { source_span: SourceSpan { offset, length }, - expr: self.clone(), + expr: BlockValue { + items, + result: Box::new(res), + }, } .into()) } @@ -57,11 +61,14 @@ impl Print for ValDef { fn print(&self, w: &mut dyn Printer) -> Result { let offset = w.current_pos(); write!(w, "val v{} = ", self.id)?; - self.rhs.print(w)?; + let rhs = self.rhs.print(w)?; let length = w.current_pos() - offset; Ok(Spanned { source_span: SourceSpan { offset, length }, - expr: self.clone(), + expr: ValDef { + id: self.id, + rhs: Box::new(rhs), + }, } .into()) } @@ -85,14 +92,17 @@ impl Print for ValUse { impl Print for Append { fn print(&self, w: &mut dyn Printer) -> Result { let offset = w.current_pos(); - self.input.print(w)?; + let input = self.input.print(w)?; write!(w, ".append(")?; - self.col_2.print(w)?; + let col_2 = self.col_2.print(w)?; write!(w, ")")?; let length = w.current_pos() - offset; Ok(Spanned { source_span: SourceSpan { offset, length }, - expr: self.clone(), + expr: Append { + input: Box::new(input), + col_2: Box::new(col_2), + }, } .into()) } @@ -101,13 +111,18 @@ impl Print for Append { impl Print for BinOp { fn print(&self, w: &mut dyn Printer) -> Result { let offset = w.current_pos(); - self.left.print(w)?; + let left = self.left.print(w)?; write!(w, " {} ", self.kind)?; - self.right.print(w)?; + let right = self.right.print(w)?; let length = w.current_pos() - offset; + // dbg!(offset, length); Ok(Spanned { source_span: SourceSpan { offset, length }, - expr: self.clone(), + expr: BinOp { + kind: self.kind, + left: Box::new(left), + right: Box::new(right), + }, } .into()) } @@ -213,7 +228,7 @@ mod tests { use super::*; - fn check(expr: Expr, expected_tree: expect_test::Expect) { + fn check_pretty(expr: Expr, expected_tree: expect_test::Expect) { let print_buf = String::new(); let mut w = PosTrackingWriter { print_buf, @@ -224,6 +239,17 @@ mod tests { expected_tree.assert_eq(w.get_buf()); } + fn check_spans(expr: Expr, expected_tree: expect_test::Expect) { + let print_buf = String::new(); + let mut w = PosTrackingWriter { + print_buf, + current_pos: 0, + current_indent: 0, + }; + let spanned_expr = expr.print(&mut w).unwrap(); + expected_tree.assert_eq(format!("{:?}", spanned_expr).as_str()); + } + #[test] fn print_block() { let val_id = 1.into(); @@ -244,7 +270,7 @@ mod tests { } .into(), ); - check( + check_pretty( expr, expect![[r#" { @@ -282,8 +308,8 @@ mod tests { } .into(), ); - check( - expr, + check_pretty( + expr.clone(), expect![[r#" { val v1 = 4 / 2 @@ -291,5 +317,12 @@ mod tests { } "#]], ); + + check_spans( + expr, + expect![[ + r#"BlockValue(Spanned { source_span: SourceSpan { offset: 0, length: 30 }, expr: BlockValue { items: [ValDef(Spanned { source_span: SourceSpan { offset: 6, length: 14 }, expr: ValDef { id: ValId(1), rhs: BinOp(Spanned { source_span: SourceSpan { offset: 15, length: 5 }, expr: BinOp { kind: Arith(Divide), left: Const("4: SInt"), right: Const("2: SInt") } }) } })], result: ValUse(ValUse { val_id: ValId(1), tpe: SInt }) } })"# + ]], + ); } } From e32014347d7c0b499974f57b694a11c307e58890 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 22 Sep 2023 13:19:57 +0300 Subject: [PATCH 22/74] rework wrapped EvalError variants, add custom Display impl for wrapped variants; --- Cargo.toml | 12 +- ergotree-interpreter/src/eval.rs | 3 +- ergotree-interpreter/src/eval/error.rs | 195 +++++++++++++++++-------- ergotree-ir/Cargo.toml | 1 + ergotree-ir/src/pretty_printer.rs | 2 +- ergotree-ir/src/source_span.rs | 6 + 6 files changed, 154 insertions(+), 65 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 202b75360..49c8a263d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ members = [ "bindings/ergo-lib-wasm", "bindings/ergo-lib-c-core", "bindings/ergo-lib-c", - "bindings/ergo-lib-jni" + "bindings/ergo-lib-jni", ] [workspace.package] @@ -37,7 +37,7 @@ ergo-merkle-tree = { version = "^0.11.1", path = "./ergo-merkle-tree" } ergo-rest = { version = "^0.9.1", path = "./ergo-rest" } ergo-lib = { version = "^0.24.1", path = "./ergo-lib"} k256 = { version = "0.13.1", features = ["arithmetic", "ecdsa"] } -elliptic-curve = {version = "0.12", features = [ "ff"]} +elliptic-curve = { version = "0.12", features = ["ff"] } thiserror = "1" bounded-vec = { version = "^0.7.0" } bitvec = { version = "1.0.1" } @@ -52,9 +52,12 @@ lazy_static = "1.4" bs58 = "0.4.0" base16 = "0.2.1" base64 = "0.13.0" -indexmap = {version ="1.3.2", features = ["serde"]} +indexmap = { version = "1.3.2", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", features = ["arbitrary_precision", "preserve_order"] } +serde_json = { version = "1.0", features = [ + "arbitrary_precision", + "preserve_order", +] } serde_with = { version = "1.9.1", features = ["json"] } rand = "0.8.5" bytes = "1.1" @@ -67,6 +70,7 @@ bounded-integer = { version = "^0.5", features = ["types"] } url = "2.2" getrandom = { version = "0.2.7" } itertools = "0.10.3" +miette = { version = "5", features = ["fancy"] } # dev-dependencies proptest = { version = "=1.0", default-features = false, features = ["std"] } diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs index 3fcf703b6..84c82474f 100644 --- a/ergotree-interpreter/src/eval.rs +++ b/ergotree-interpreter/src/eval.rs @@ -146,7 +146,8 @@ pub fn reduce_to_crypto( .print(&mut printer) .map_err(|e| EvalError::Misc(format!("printer error: {}", e)))?; let printed_expr_str = printer.get_buf(); - inner(&spanned_expr, env, ctx_clone).map_err(|e| e.wrap_with_src(printed_expr_str.to_string())) + inner(&spanned_expr, env, ctx_clone) + .map_err(|e| e.wrap_spanned_with_src(printed_expr_str.to_string())) } /// Expects SigmaProp constant value and returns it's value. Otherwise, returns an error. diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 1d4d2fc95..961f5fa21 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -1,4 +1,9 @@ +use miette::miette; +use miette::LabeledSpan; +use std::fmt::Display; + use bounded_vec::BoundedVecOutOfBounds; +use derive_more::TryInto; use ergotree_ir::ergo_tree::ErgoTreeError; use ergotree_ir::mir::constant::TryExtractFromError; use ergotree_ir::serialization::SigmaParsingError; @@ -12,7 +17,7 @@ use super::cost_accum::CostError; use super::env::Env; /// Interpreter errors -#[derive(Error, PartialEq, Eq, Debug, Clone)] +#[derive(Error, PartialEq, Eq, Debug, Clone, TryInto)] pub enum EvalError { /// AVL tree errors #[error("AvlTree: {0}")] @@ -65,58 +70,85 @@ pub enum EvalError { /// Scorex serialization parsing error #[error("Serialization parsing error: {0}")] ScorexParsingError(#[from] ScorexParsingError), - /// Wrapped error with source span and environment - #[error("eval error: {error}, details: {details:?}")] - Wrapped { - /// eval error - error: Box, - /// error details - details: EvalErrorDetails, - }, + /// Wrapped error with source span and source code + #[error("eval error: {0}")] + SpannedWithSource(SpannedWithSourceEvalError), + /// Wrapped error with source span + #[error("eval error: {0:?}")] + Spanned(SpannedEvalError), } +/// Wrapped error with source span #[derive(PartialEq, Eq, Debug, Clone)] -pub struct EvalErrorDetails { - /// source span +pub struct SpannedEvalError { + /// eval error + error: Box, + /// source span for the expression where error occurred source_span: SourceSpan, - /// environment after evaluation + /// environment at the time when error occurred + env: Env, +} + +/// Wrapped error with source span and source code +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SpannedWithSourceEvalError { + /// eval error + error: Box, + /// source span for the expression where error occurred + source_span: SourceSpan, + /// environment at the time when error occurred env: Env, /// source code - source: Option, + source: String, +} + +impl Display for SpannedWithSourceEvalError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + #[allow(clippy::unwrap_used)] + miette::set_hook(Box::new(|_| { + Box::new( + miette::MietteHandlerOpts::new() + .terminal_links(false) + .unicode(false) + .color(false) + .context_lines(5) + .tab_width(2) + .build(), + ) + })) + .unwrap(); + let err_msg = self.error.to_string(); + let report = miette!( + labels = vec![LabeledSpan::at(self.source_span, err_msg,)], + // help = "Help msg", + "Evaluation error" + ) + .with_source_code(self.source.clone()); + write!(f, "{:?}", report) + } } impl EvalError { /// Wrap eval error with source span pub fn wrap(self, source_span: SourceSpan, env: Env) -> Self { - EvalError::Wrapped { + EvalError::Spanned(SpannedEvalError { error: Box::new(self), - details: EvalErrorDetails { - source_span, - env, - source: None, - }, - } + source_span, + env, + }) } /// Wrap eval error with source code - pub fn wrap_with_src(self, source: String) -> Self { + pub fn wrap_spanned_with_src(self, source: String) -> Self { + #[allow(clippy::panic)] match self { - EvalError::Wrapped { error, details } => EvalError::Wrapped { - error, - details: EvalErrorDetails { - source_span: details.source_span, - env: details.env, - source: Some(source), - }, - }, - e => EvalError::Wrapped { - error: Box::new(e), - details: EvalErrorDetails { - source_span: SourceSpan::empty(), - env: Env::empty(), - source: Some(source), - }, - }, + EvalError::Spanned(e) => EvalError::SpannedWithSource(SpannedWithSourceEvalError { + error: e.error, + source_span: e.source_span, + env: e.env, + source, + }), + e => panic!("Expected Spanned, got {:?}", e), } } } @@ -129,10 +161,7 @@ impl ExtResultEvalError for Result { fn enrich_err(self, span: SourceSpan, env: Env) -> Result { self.map_err(|e| match e { // skip already wrapped errors - w @ EvalError::Wrapped { - error: _, - details: _, - } => w, + w @ EvalError::Spanned { .. } => w, e => e.wrap(span, env), }) } @@ -157,6 +186,8 @@ mod tests { use sigma_test_util::force_any_val; use crate::eval::context::Context; + use crate::eval::error::SpannedEvalError; + use crate::eval::error::SpannedWithSourceEvalError; use crate::eval::tests::try_eval_out; fn check(expr: Expr, expected_tree: expect_test::Expect) { @@ -164,32 +195,67 @@ mod tests { let spanned_expr = expr.print(&mut w).unwrap(); dbg!(&spanned_expr); let ctx = Rc::new(force_any_val::()); - let err_raw = try_eval_out::(&spanned_expr, ctx).err().unwrap(); - // let err = err_raw.wrap_with_src(w.get_buf().to_string()); - let err_msg = format!("{:?}", err_raw); - expected_tree.assert_eq(&err_msg); + let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, ctx) + .err() + .unwrap() + .try_into() + .unwrap(); + let err = SpannedWithSourceEvalError { + error: err_raw.error, + source_span: err_raw.source_span, + env: err_raw.env, + source: w.get_buf().to_string(), + }; + expected_tree.assert_eq(&err.to_string()); } + #[ignore = "expect test fails on self-generated string"] #[test] fn pretty_binop_div_zero() { - let val_id = 1.into(); + let lhs_val_id = 1.into(); + let rhs_val_id = 2.into(); + let res_val_id = 3.into(); let expr = Expr::BlockValue( BlockValue { - items: vec![ValDef { - id: val_id, - rhs: Box::new( - BinOp { - kind: ArithOp::Divide.into(), - left: Expr::Const(1i32.into()).into(), - right: Expr::Const(0i32.into()).into(), - } - .into(), - ), - } - .into()], + items: vec![ + ValDef { + id: lhs_val_id, + rhs: Box::new(Expr::Const(42i32.into())), + } + .into(), + ValDef { + id: rhs_val_id, + rhs: Box::new(Expr::Const(0i32.into())), + } + .into(), + ValDef { + id: res_val_id, + rhs: Box::new( + BinOp { + kind: ArithOp::Divide.into(), + left: Box::new( + ValUse { + val_id: lhs_val_id, + tpe: SType::SInt, + } + .into(), + ), + right: Box::new( + ValUse { + val_id: rhs_val_id, + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ), + } + .into(), + ], result: Box::new( ValUse { - val_id, + val_id: res_val_id, tpe: SType::SInt, } .into(), @@ -200,6 +266,17 @@ mod tests { check( expr, expect![[r#" + x Evaluation error + ,-[1:1] + 1 | { + 2 | val v1 = 42 + 3 | val v2 = 0 + 4 | val v3 = v1 / v2 + : ^^^|^^^ + : `-- Arithmetic exception: (42) / (0) resulted in exception + 5 | v3 + 6 | } + `---- "#]], ) } diff --git a/ergotree-ir/Cargo.toml b/ergotree-ir/Cargo.toml index 8d2a78879..7ce35189d 100644 --- a/ergotree-ir/Cargo.toml +++ b/ergotree-ir/Cargo.toml @@ -37,6 +37,7 @@ num256 = "0.3.1" impl-trait-for-tuples = "0.2.0" strum = "0.21" strum_macros = "0.21" +miette = { workspace = true } [features] default = ["json"] diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index f5cc2c386..71241eb52 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -190,7 +190,7 @@ impl Printer for PosTrackingWriter { } impl PosTrackingWriter { - const INDENT: usize = 4; + const INDENT: usize = 2; /// Create new printer pub fn new() -> Self { diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 10bfe7665..19646c5db 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -25,6 +25,12 @@ impl SourceSpan { } } +impl From for miette::SourceSpan { + fn from(value: SourceSpan) -> Self { + miette::SourceSpan::new(value.offset.into(), value.length.into()) + } +} + /// Wrapper for Expr with source position #[derive(PartialEq, Eq, Debug, Clone)] pub struct Spanned { From bf365ddc3dfc0bc069ea98ec546514eb422e5b81 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 9 Aug 2023 12:31:18 +0300 Subject: [PATCH 23/74] add source span test eval error; --- ergotree-interpreter/src/eval/error.rs | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 961f5fa21..07cbe59f5 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -172,6 +172,7 @@ impl ExtResultEvalError for Result { mod tests { use std::rc::Rc; + use ergotree_ir::source_span::SourceSpan; use expect_test::expect; use ergotree_ir::mir::bin_op::ArithOp; @@ -280,4 +281,75 @@ mod tests { "#]], ) } + + #[test] + fn span_binop_div_zero() { + let lhs_val_id = 1.into(); + let rhs_val_id = 2.into(); + let res_val_id = 3.into(); + let expr = Expr::BlockValue( + BlockValue { + items: vec![ + ValDef { + id: lhs_val_id, + rhs: Box::new(Expr::Const(42i32.into())), + } + .into(), + ValDef { + id: rhs_val_id, + rhs: Box::new(Expr::Const(0i32.into())), + } + .into(), + ValDef { + id: res_val_id, + rhs: Box::new( + BinOp { + kind: ArithOp::Divide.into(), + left: Box::new( + ValUse { + val_id: lhs_val_id, + tpe: SType::SInt, + } + .into(), + ), + right: Box::new( + ValUse { + val_id: rhs_val_id, + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ), + } + .into(), + ], + result: Box::new( + ValUse { + val_id: res_val_id, + tpe: SType::SInt, + } + .into(), + ), + } + .into(), + ); + let mut w = PosTrackingWriter::new(); + let spanned_expr = expr.print(&mut w).unwrap(); + dbg!(&spanned_expr); + let ctx = Rc::new(force_any_val::()); + let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, ctx) + .err() + .unwrap() + .try_into() + .unwrap(); + assert_eq!( + err_raw.source_span, + SourceSpan { + offset: 40, + length: 7 + } + ); + } } From 9f8dfea9cd67575e72923e85ef7af3b4fef26dc2 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 11 Aug 2023 12:51:44 +0300 Subject: [PATCH 24/74] impl Print for GlobalVars; --- ergotree-ir/src/mir/global_vars.rs | 15 +++++++++++++++ ergotree-ir/src/pretty_printer.rs | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/ergotree-ir/src/mir/global_vars.rs b/ergotree-ir/src/mir/global_vars.rs index b2b40c196..ce5a35708 100644 --- a/ergotree-ir/src/mir/global_vars.rs +++ b/ergotree-ir/src/mir/global_vars.rs @@ -1,5 +1,7 @@ //! Global variables +use std::fmt::Display; + use crate::has_opcode::HasOpCode; use crate::serialization::op_code::OpCode; use crate::types::stype::SType; @@ -49,6 +51,19 @@ impl HasOpCode for GlobalVars { } } +impl Display for GlobalVars { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + GlobalVars::SelfBox => write!(f, "SELF"), + GlobalVars::Inputs => write!(f, "INPUTS"), + GlobalVars::Outputs => write!(f, "OUTPUTS"), + GlobalVars::Height => write!(f, "HEIGHT"), + GlobalVars::MinerPubKey => write!(f, "MINER_PUBKEY"), + GlobalVars::GroupGenerator => write!(f, "GROUP_GENERATOR"), + } + } +} + #[cfg(test)] #[cfg(feature = "arbitrary")] mod tests { diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 71241eb52..4f07998d7 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -9,6 +9,7 @@ use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::constant::Constant; use crate::mir::expr::Expr; +use crate::mir::global_vars::GlobalVars; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; use crate::source_span::SourceSpan; @@ -128,6 +129,13 @@ impl Print for BinOp { } } +impl Print for GlobalVars { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "{}", self)?; + Ok(self.clone().into()) + } +} + #[allow(clippy::panic)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { @@ -138,6 +146,7 @@ impl Print for Expr { Expr::ValUse(v) => v.print(w), Expr::Const(v) => v.print(w), Expr::BinOp(v) => v.expr().print(w), + Expr::GlobalVars(v) => v.print(w), e => panic!("Not implemented: {:?}", e), } } From e26d18e9305c98504f3d5de5b5ae36a08f93cf18 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 22 Sep 2023 13:21:19 +0300 Subject: [PATCH 25/74] impl pretty printing for ByIndex and add out of bounds error test; --- Cargo.toml | 2 +- ergotree-interpreter/src/eval/error.rs | 50 ++++++++++++++++++++++++++ ergotree-interpreter/src/eval/expr.rs | 4 +-- ergotree-ir/src/mir/expr.rs | 4 +-- ergotree-ir/src/pretty_printer.rs | 19 ++++++++++ ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 6 ++-- 7 files changed, 79 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 49c8a263d..4c49a8063 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,7 @@ proptest = { version = "=1.0", default-features = false, features = ["std"] } proptest-derive = "0.3" pretty_assertions = "1.3" wasm-bindgen-test = "0.3.37" -expect-test = "1.0.1" +expect-test = "1.4.1" [profile.release] # Tell `rustc` to optimize for small code size. diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index 07cbe59f5..d878bc8c6 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -172,6 +172,8 @@ impl ExtResultEvalError for Result { mod tests { use std::rc::Rc; + use ergotree_ir::mir::coll_by_index::ByIndex; + use ergotree_ir::mir::global_vars::GlobalVars; use ergotree_ir::source_span::SourceSpan; use expect_test::expect; @@ -352,4 +354,52 @@ mod tests { } ); } + + #[ignore = "expect test fails on self-generated string"] + #[test] + fn pretty_out_of_bounds() { + // OUTPUTS(1) should be out of bounds error in: + // { + // val v1 = 1 + // OUPUTS(v1) + // } + let v1_id = 1.into(); + let expr = Expr::BlockValue( + BlockValue { + items: vec![ValDef { + id: v1_id, + rhs: Box::new(Expr::Const(99999999i32.into())), + } + .into()], + result: Box::new(Expr::ByIndex( + ByIndex::new( + Expr::GlobalVars(GlobalVars::Outputs), + ValUse { + val_id: v1_id, + tpe: SType::SInt, + } + .into(), + None, + ) + .unwrap() + .into(), + )), + } + .into(), + ); + check( + expr, + expect![[r#" + x Evaluation error + ,-[1:1] + 1 | { + 2 | val v1 = 99999999 + 3 | OUTPUTS(v1) + : ^^|^ + : `-- error: ByIndex: index Int(99999999) out of bounds for collection size 1 + 4 | } + `---- + "#]], + ) + } } diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 6e8b6fe98..2c04f17a4 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -3,11 +3,11 @@ use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; -use super::error::ExtResultEvalError; use super::Env; use super::EvalContext; use super::EvalError; use super::Evaluable; +use super::error::ExtResultEvalError; impl Evaluable for Expr { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { @@ -54,7 +54,7 @@ impl Evaluable for Expr { Expr::Downcast(op) => op.eval(env, ctx), Expr::If(op) => op.eval(env, ctx), Expr::Append(op) => op.expr().eval(env, ctx), - Expr::ByIndex(op) => op.eval(env, ctx), + Expr::ByIndex(op) => op.expr().eval(env, ctx), Expr::ExtractScriptBytes(op) => op.eval(env, ctx), Expr::SizeOf(op) => op.eval(env, ctx), Expr::Slice(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index bfcc6c87d..d20a3fef0 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -167,7 +167,7 @@ pub enum Expr { /// Box id, Blake2b256 hash of this box's content, basically equals to `blake2b256(bytes)` ExtractId(ExtractId), /// Collection, get element by index - ByIndex(ByIndex), + ByIndex(Spanned), /// Collection size SizeOf(SizeOf), /// Collection slice @@ -265,7 +265,7 @@ impl Expr { Expr::Upcast(v) => v.tpe(), Expr::Downcast(v) => v.tpe(), Expr::If(v) => v.tpe(), - Expr::ByIndex(v) => v.tpe(), + Expr::ByIndex(v) => v.expr().tpe(), Expr::ExtractScriptBytes(v) => v.tpe(), Expr::SizeOf(v) => v.tpe(), Expr::Slice(v) => v.tpe(), diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 4f07998d7..7fd19d388 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -7,6 +7,7 @@ use thiserror::Error; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; +use crate::mir::coll_by_index::ByIndex; use crate::mir::constant::Constant; use crate::mir::expr::Expr; use crate::mir::global_vars::GlobalVars; @@ -136,6 +137,23 @@ impl Print for GlobalVars { } } +impl Print for ByIndex { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + let offset = w.current_pos(); + write!(w, "(")?; + let index = self.index.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: ByIndex::new(input, index, self.default.clone()).unwrap(), + } + .into()) + } +} + #[allow(clippy::panic)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { @@ -147,6 +165,7 @@ impl Print for Expr { Expr::Const(v) => v.print(w), Expr::BinOp(v) => v.expr().print(w), Expr::GlobalVars(v) => v.print(w), + Expr::ByIndex(v) => v.expr().print(w), e => panic!("Not implemented: {:?}", e), } } diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index bf25c0bcf..1bc4d1bd5 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -264,7 +264,7 @@ impl SigmaSerializable for Expr { Expr::Upcast(op) => op.sigma_serialize_w_opcode(w), Expr::Downcast(op) => op.sigma_serialize_w_opcode(w), Expr::If(op) => op.sigma_serialize_w_opcode(w), - Expr::ByIndex(op) => op.sigma_serialize_w_opcode(w), + Expr::ByIndex(op) => op.expr().sigma_serialize_w_opcode(w), Expr::ExtractScriptBytes(op) => op.sigma_serialize_w_opcode(w), Expr::SizeOf(op) => op.sigma_serialize_w_opcode(w), Expr::Slice(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 19646c5db..cb31b8262 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -3,6 +3,7 @@ use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; +use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; use crate::mir::val_def::ValDef; @@ -64,6 +65,7 @@ into_expr!(Append); into_expr!(BlockValue); into_expr!(ValDef); into_expr!(BinOp); +into_expr!(ByIndex); impl From for Spanned { fn from(v: T) -> Self { @@ -92,7 +94,7 @@ impl Expr { Expr::CalcSha256(_) => todo!(), Expr::Context => todo!(), Expr::Global => todo!(), - Expr::GlobalVars(_) => todo!(), + Expr::GlobalVars(_) => SourceSpan::empty(), Expr::FuncValue(_) => todo!(), Expr::Apply(_) => todo!(), Expr::MethodCall(_) => todo!(), @@ -119,7 +121,7 @@ impl Expr { Expr::ExtractScriptBytes(_) => todo!(), Expr::ExtractCreationInfo(_) => todo!(), Expr::ExtractId(_) => todo!(), - Expr::ByIndex(_) => todo!(), + Expr::ByIndex(op) => op.source_span, Expr::SizeOf(_) => todo!(), Expr::Slice(_) => todo!(), Expr::Fold(_) => todo!(), From 955e751849c5c65382263df027a7c6b2d06d6ba9 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 15 Aug 2023 15:51:19 +0300 Subject: [PATCH 26/74] add span check in pretty error tests; --- ergotree-interpreter/src/eval/error.rs | 153 ++++++++----------------- ergotree-ir/src/pretty_printer.rs | 1 - ergotree-ir/src/source_span.rs | 9 ++ 3 files changed, 54 insertions(+), 109 deletions(-) diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index d878bc8c6..ca410e829 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -167,7 +167,7 @@ impl ExtResultEvalError for Result { } } -#[allow(clippy::unwrap_used)] +#[allow(clippy::unwrap_used, unused_imports, dead_code)] #[cfg(test)] mod tests { use std::rc::Rc; @@ -212,80 +212,21 @@ mod tests { expected_tree.assert_eq(&err.to_string()); } - #[ignore = "expect test fails on self-generated string"] - #[test] - fn pretty_binop_div_zero() { - let lhs_val_id = 1.into(); - let rhs_val_id = 2.into(); - let res_val_id = 3.into(); - let expr = Expr::BlockValue( - BlockValue { - items: vec![ - ValDef { - id: lhs_val_id, - rhs: Box::new(Expr::Const(42i32.into())), - } - .into(), - ValDef { - id: rhs_val_id, - rhs: Box::new(Expr::Const(0i32.into())), - } - .into(), - ValDef { - id: res_val_id, - rhs: Box::new( - BinOp { - kind: ArithOp::Divide.into(), - left: Box::new( - ValUse { - val_id: lhs_val_id, - tpe: SType::SInt, - } - .into(), - ), - right: Box::new( - ValUse { - val_id: rhs_val_id, - tpe: SType::SInt, - } - .into(), - ), - } - .into(), - ), - } - .into(), - ], - result: Box::new( - ValUse { - val_id: res_val_id, - tpe: SType::SInt, - } - .into(), - ), - } - .into(), - ); - check( - expr, - expect![[r#" - x Evaluation error - ,-[1:1] - 1 | { - 2 | val v1 = 42 - 3 | val v2 = 0 - 4 | val v3 = v1 / v2 - : ^^^|^^^ - : `-- Arithmetic exception: (42) / (0) resulted in exception - 5 | v3 - 6 | } - `---- - "#]], - ) + fn check_error_span(expr: Expr, expected_span: SourceSpan) { + let mut w = PosTrackingWriter::new(); + let spanned_expr = expr.print(&mut w).unwrap(); + dbg!(&spanned_expr); + let ctx = Rc::new(force_any_val::()); + let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, ctx) + .err() + .unwrap() + .try_into() + .unwrap(); + assert_eq!(err_raw.source_span, expected_span); } #[test] - fn span_binop_div_zero() { + fn pretty_binop_div_zero() { let lhs_val_id = 1.into(); let rhs_val_id = 2.into(); let res_val_id = 3.into(); @@ -337,32 +278,27 @@ mod tests { } .into(), ); - let mut w = PosTrackingWriter::new(); - let spanned_expr = expr.print(&mut w).unwrap(); - dbg!(&spanned_expr); - let ctx = Rc::new(force_any_val::()); - let err_raw: SpannedEvalError = try_eval_out::(&spanned_expr, ctx) - .err() - .unwrap() - .try_into() - .unwrap(); - assert_eq!( - err_raw.source_span, - SourceSpan { - offset: 40, - length: 7 - } - ); + // check( + // expr, + // expect![[r#" + // x Evaluation error + // ,-[1:1] + // 1 | { + // 2 | val v1 = 42 + // 3 | val v2 = 0 + // 4 | val v3 = v1 / v2 + // : ^^^|^^^ + // : `-- Arithmetic exception: (42) / (0) resulted in exception + // 5 | v3 + // 6 | } + // `---- + // "#]], + // ); + check_error_span(expr, (40, 7).into()); } - #[ignore = "expect test fails on self-generated string"] #[test] fn pretty_out_of_bounds() { - // OUTPUTS(1) should be out of bounds error in: - // { - // val v1 = 1 - // OUPUTS(v1) - // } let v1_id = 1.into(); let expr = Expr::BlockValue( BlockValue { @@ -387,19 +323,20 @@ mod tests { } .into(), ); - check( - expr, - expect![[r#" - x Evaluation error - ,-[1:1] - 1 | { - 2 | val v1 = 99999999 - 3 | OUTPUTS(v1) - : ^^|^ - : `-- error: ByIndex: index Int(99999999) out of bounds for collection size 1 - 4 | } - `---- - "#]], - ) + // check( + // expr, + // expect![[r#" + // x Evaluation error + // ,-[1:1] + // 1 | { + // 2 | val v1 = 99999999 + // 3 | OUTPUTS(v1) + // : ^^|^ + // : `-- error: ByIndex: index Int(99999999) out of bounds for collection size 1 + // 4 | } + // `---- + // "#]], + // ); + check_error_span(expr, (31, 4).into()); } } diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 7fd19d388..1894ffa69 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -78,7 +78,6 @@ impl Print for ValDef { impl Print for Constant { fn print(&self, w: &mut dyn Printer) -> Result { - // TODO: implement Display for Literal write!(w, "{:?}", self.v)?; Ok(self.clone().into()) } diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index cb31b8262..142e700c8 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -26,6 +26,15 @@ impl SourceSpan { } } +impl From<(usize, usize)> for SourceSpan { + fn from(value: (usize, usize)) -> Self { + SourceSpan { + offset: value.0, + length: value.1, + } + } +} + impl From for miette::SourceSpan { fn from(value: SourceSpan) -> Self { miette::SourceSpan::new(value.offset.into(), value.length.into()) From a5e40f797ddafc6841a336c24f384c09376860ed Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 15 Aug 2023 17:29:46 +0300 Subject: [PATCH 27/74] impl Display impl for Constant (primitive and composite types); --- .../src/eval/deserialize_context.rs | 12 ++-- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-interpreter/src/eval/get_var.rs | 5 +- .../prover/context_extension.rs | 7 +++ ergotree-ir/src/mir/constant.rs | 63 +++++++++++++++++++ 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/ergotree-interpreter/src/eval/deserialize_context.rs b/ergotree-interpreter/src/eval/deserialize_context.rs index cbb88fcd2..49485e389 100644 --- a/ergotree-interpreter/src/eval/deserialize_context.rs +++ b/ergotree-interpreter/src/eval/deserialize_context.rs @@ -14,8 +14,12 @@ impl Evaluable for DeserializeContext { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { match ctx.ctx.extension.values.get(&self.id) { Some(c) => { - if c.tpe != SType::SColl(SType::SByte.into()) { - Err(EvalError::UnexpectedExpr(format!("DeserializeContext: expected extension value to have type SColl(SByte), got {:?}", c.tpe))) + let expected_tpe = SType::SColl(SType::SByte.into()); + if c.tpe != expected_tpe { + Err(EvalError::UnexpectedExpr(format!( + "DeserializeContext: expected extension value to have type {:?} got {:?}", + expected_tpe, c.tpe + ))) } else { let bytes = c.v.clone().try_extract_into::>()?; let expr = Expr::sigma_parse_bytes(bytes.as_slice())?; @@ -26,8 +30,8 @@ impl Evaluable for DeserializeContext { } } None => Err(EvalError::NotFound(format!( - "DeserializeContext: no value with id {} in context extension", - self.id + "DeserializeContext: no value with id {} in context extension map {}", + self.id, ctx.ctx.extension ))), } } diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 2c04f17a4..651999dd5 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -40,7 +40,7 @@ impl Evaluable for Expr { )), Expr::Collection(op) => op.eval(env, ctx), Expr::ValDef(_) => Err(EvalError::UnexpectedExpr( - ("ValDef is evaluated in BlockValue").to_string(), + ("ValDef should be evaluated in BlockValue").to_string(), )), Expr::And(op) => op.eval(env, ctx), Expr::Or(op) => op.eval(env, ctx), diff --git a/ergotree-interpreter/src/eval/get_var.rs b/ergotree-interpreter/src/eval/get_var.rs index 07bbbfb7c..1ac5e34e6 100644 --- a/ergotree-interpreter/src/eval/get_var.rs +++ b/ergotree-interpreter/src/eval/get_var.rs @@ -1,4 +1,3 @@ -// use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::constant::TryExtractFromError; use ergotree_ir::mir::get_var::GetVar; use ergotree_ir::mir::value::Value; @@ -14,8 +13,8 @@ impl Evaluable for GetVar { None => Ok(Value::Opt(None.into())), Some(v) if v.tpe == self.var_tpe => Ok((Some(v.v.clone())).into()), Some(v) => Err(TryExtractFromError(format!( - "GetVar: expected {:?}, found {:?}", - self.var_tpe, v.tpe + "GetVar: expected extension value id {} to have type {:?}, found {:?} in context extension map {}", + self.var_id, self.var_tpe, v, ctx.ctx.extension )) .into()), } diff --git a/ergotree-interpreter/src/sigma_protocol/prover/context_extension.rs b/ergotree-interpreter/src/sigma_protocol/prover/context_extension.rs index 09aed3e41..ed245147f 100644 --- a/ergotree-interpreter/src/sigma_protocol/prover/context_extension.rs +++ b/ergotree-interpreter/src/sigma_protocol/prover/context_extension.rs @@ -7,6 +7,7 @@ use ergotree_ir::serialization::SigmaSerializable; use ergotree_ir::serialization::SigmaSerializeResult; use indexmap::IndexMap; use std::convert::TryFrom; +use std::fmt; use thiserror::Error; /// User-defined variables to be put into context @@ -25,6 +26,12 @@ impl ContextExtension { } } +impl fmt::Display for ContextExtension { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.values.iter()).finish() + } +} + impl SigmaSerializable for ContextExtension { fn sigma_serialize(&self, w: &mut W) -> SigmaSerializeResult { w.put_u8(self.values.len() as u8)?; diff --git a/ergotree-ir/src/mir/constant.rs b/ergotree-ir/src/mir/constant.rs index e3ff14b09..be58514c0 100644 --- a/ergotree-ir/src/mir/constant.rs +++ b/ergotree-ir/src/mir/constant.rs @@ -88,6 +88,12 @@ impl std::fmt::Debug for Constant { } } +impl std::fmt::Display for Constant { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.v.fmt(f) + } +} + impl std::fmt::Debug for Literal { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { @@ -112,6 +118,63 @@ impl std::fmt::Debug for Literal { } } +impl std::fmt::Display for Literal { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => { + write!(f, "Coll[Byte]("); + for (i, b) in i8_bytes.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", b)?; + } + write!(f, ")") + } + Literal::Coll(CollKind::WrappedColl { elem_tpe, items }) => { + write!(f, "Coll[{}](", elem_tpe)?; + for (i, item) in items.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + item.fmt(f)?; + } + write!(f, ")") + } + Literal::Opt(boxed_opt) => { + if let Some(v) = &**boxed_opt { + write!(f, "Some(")?; + v.fmt(f)?; + write!(f, ")") + } else { + write!(f, "None") + } + } + Literal::Tup(items) => { + write!(f, "(")?; + for (i, item) in items.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + item.fmt(f)?; + } + write!(f, ")") + } + Literal::Unit => write!(f, "()"), + Literal::Boolean(v) => v.fmt(f), + Literal::Byte(v) => v.fmt(f), + Literal::Short(v) => v.fmt(f), + Literal::Int(v) => v.fmt(f), + Literal::Long(v) => write!(f, "{}L", v), + Literal::BigInt(v) => v.fmt(f), + Literal::SigmaProp(v) => v.fmt(f), + Literal::GroupElement(v) => v.fmt(f), + Literal::AvlTree(v) => v.fmt(f), + Literal::CBox(v) => v.fmt(f), + } + } +} + impl From<()> for Literal { fn from(_: ()) -> Literal { Literal::Unit From cf0efe30a4733b0401290d9df573038b71d68e14 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 16 Aug 2023 14:49:22 +0300 Subject: [PATCH 28/74] Display impl for SType; --- ergotree-ir/src/types/sfunc.rs | 14 ++++++++++++++ ergotree-ir/src/types/stuple.rs | 13 +++++++++++++ ergotree-ir/src/types/stype.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/ergotree-ir/src/types/sfunc.rs b/ergotree-ir/src/types/sfunc.rs index f838a3304..1add72303 100644 --- a/ergotree-ir/src/types/sfunc.rs +++ b/ergotree-ir/src/types/sfunc.rs @@ -15,6 +15,20 @@ pub struct SFunc { pub tpe_params: Vec, } +impl std::fmt::Display for SFunc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "(")?; + for (i, item) in self.t_dom.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + item.fmt(f)?; + } + write!(f, ") => ")?; + self.t_range.fmt(f) + } +} + impl SFunc { /// Create new SFunc pub fn new(t_dom: Vec, t_range: SType) -> Self { diff --git a/ergotree-ir/src/types/stuple.rs b/ergotree-ir/src/types/stuple.rs index 95afe5947..51f992d14 100644 --- a/ergotree-ir/src/types/stuple.rs +++ b/ergotree-ir/src/types/stuple.rs @@ -34,6 +34,19 @@ impl std::fmt::Debug for STuple { } } +impl std::fmt::Display for STuple { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "(")?; + for (i, item) in self.items.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + item.fmt(f)?; + } + write!(f, ")") + } +} + impl STuple { /// Create a tuple type for a given type pair pub fn pair(t1: SType, t2: SType) -> Self { diff --git a/ergotree-ir/src/types/stype.rs b/ergotree-ir/src/types/stype.rs index eba90fea1..bc926bdfa 100644 --- a/ergotree-ir/src/types/stype.rs +++ b/ergotree-ir/src/types/stype.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::convert::TryInto; +use std::fmt::Debug; use impl_trait_for_tuples::impl_for_tuples; @@ -126,6 +127,34 @@ impl From for SType { } } +impl std::fmt::Display for SType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SType::STypeVar(t) => write!(f, "{}", t.as_string()), + SType::SAny => write!(f, "Any"), + SType::SUnit => write!(f, "Unit"), + SType::SBoolean => write!(f, "Boolean"), + SType::SByte => write!(f, "Byte"), + SType::SShort => write!(f, "Short"), + SType::SInt => write!(f, "Int"), + SType::SLong => write!(f, "Long"), + SType::SBigInt => write!(f, "BigInt"), + SType::SGroupElement => write!(f, "GroupElement"), + SType::SSigmaProp => write!(f, "SigmaProp"), + SType::SBox => write!(f, "Box"), + SType::SAvlTree => write!(f, "AvlTree"), + SType::SOption(t) => write!(f, "Option[{}]", t), + SType::SColl(t) => write!(f, "Coll[{}]", t), + SType::STuple(t) => write!(f, "{}", t), + SType::SFunc(t) => write!(f, "{}", t), + SType::SContext => write!(f, "Context"), + SType::SHeader => write!(f, "Header"), + SType::SPreHeader => write!(f, "PreHeader"), + SType::SGlobal => write!(f, "Global"), + } + } +} + /// Conversion to SType pub trait LiftIntoSType { /// get SType From da54af09646677cea12432299d3a5e3cf50f5da1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 18 Aug 2023 13:05:16 +0300 Subject: [PATCH 29/74] implement Display for all Literal variants; --- ergo-chain-types/src/ec_point.rs | 9 ++++ ergotree-ir/src/mir/constant.rs | 6 +-- .../src/sigma_protocol/sigma_boolean.rs | 42 ++++++++++++++++++- .../src/sigma_protocol/sigma_boolean/cand.rs | 13 ++++++ .../src/sigma_protocol/sigma_boolean/cor.rs | 13 ++++++ .../sigma_boolean/cthreshold.rs | 15 +++++++ 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/ergo-chain-types/src/ec_point.rs b/ergo-chain-types/src/ec_point.rs index 97b89c45d..f71f4e4d6 100644 --- a/ergo-chain-types/src/ec_point.rs +++ b/ergo-chain-types/src/ec_point.rs @@ -28,6 +28,15 @@ impl std::fmt::Debug for EcPoint { } } +#[allow(clippy::unwrap_used)] +impl std::fmt::Display for EcPoint { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str(&base16::encode_lower( + &self.scorex_serialize_bytes().unwrap(), + )) + } +} + impl EcPoint { /// Number of bytes to represent any group element as byte array pub const GROUP_SIZE: usize = 33; diff --git a/ergotree-ir/src/mir/constant.rs b/ergotree-ir/src/mir/constant.rs index be58514c0..78f51a549 100644 --- a/ergotree-ir/src/mir/constant.rs +++ b/ergotree-ir/src/mir/constant.rs @@ -122,7 +122,7 @@ impl std::fmt::Display for Literal { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => { - write!(f, "Coll[Byte]("); + write!(f, "Coll[Byte](")?; for (i, b) in i8_bytes.iter().enumerate() { if i > 0 { write!(f, ", ")?; @@ -169,8 +169,8 @@ impl std::fmt::Display for Literal { Literal::BigInt(v) => v.fmt(f), Literal::SigmaProp(v) => v.fmt(f), Literal::GroupElement(v) => v.fmt(f), - Literal::AvlTree(v) => v.fmt(f), - Literal::CBox(v) => v.fmt(f), + Literal::AvlTree(v) => write!(f, "AvlTree({:?})", v), + Literal::CBox(v) => write!(f, "ErgoBox({:?})", v), } } } diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean.rs index fe0f71866..6ed07ae5d 100644 --- a/ergotree-ir/src/sigma_protocol/sigma_boolean.rs +++ b/ergotree-ir/src/sigma_protocol/sigma_boolean.rs @@ -13,6 +13,7 @@ use crate::serialization::SigmaSerializable; use ergo_chain_types::EcPoint; use std::convert::TryFrom; use std::convert::TryInto; +use std::fmt::Formatter; extern crate derive_more; use bounded_vec::BoundedVec; @@ -53,6 +54,12 @@ impl From for ProveDlog { } } +impl std::fmt::Display for ProveDlog { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "proveDlog({})", self.h) + } +} + /// Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol. /// Used in a proof that of equality of discrete logarithms (i.e., a proof of a Diffie-Hellman tuple): /// given group elements g, h, u, v, the proof convinces a verifier that the prover knows `w` such @@ -86,8 +93,18 @@ impl ProveDhTuple { } } +impl std::fmt::Display for ProveDhTuple { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "ProveDhTuple(g: {}, h: {}, u: {}, v: {})", + self.g, self.h, self.u, self.v + ) + } +} + /// Sigma proposition -#[derive(PartialEq, Eq, Debug, Clone, From)] +#[derive(PartialEq, Eq, Debug, Clone, From, derive_more::Display)] pub enum SigmaProofOfKnowledgeTree { /// public key of Diffie Hellman signature protocol ProveDhTuple(ProveDhTuple), @@ -125,6 +142,16 @@ impl HasOpCode for SigmaConjecture { } } +impl std::fmt::Display for SigmaConjecture { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + SigmaConjecture::Cand(c) => write!(f, "{}", c), + SigmaConjecture::Cor(c) => write!(f, "{}", c), + SigmaConjecture::Cthreshold(c) => write!(f, "{}", c), + } + } +} + /// Algebraic data type of sigma proposition expressions /// Values of this type are used as values of SigmaProp type #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)] @@ -246,8 +273,18 @@ impl From for SigmaBoolean { } } +impl std::fmt::Display for SigmaBoolean { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + SigmaBoolean::TrivialProp(b) => write!(f, "sigmaProp({})", b), + SigmaBoolean::ProofOfKnowledge(kt) => write!(f, "{}", kt), + SigmaBoolean::SigmaConjecture(sc) => write!(f, "{}", sc), + } + } +} + /// Proposition which can be proven and verified by sigma protocol. -#[derive(PartialEq, Eq, Debug, Clone, From, Into)] +#[derive(PartialEq, Eq, Debug, Clone, From, Into, derive_more::Display)] pub struct SigmaProp(SigmaBoolean); impl SigmaProp { @@ -295,6 +332,7 @@ impl From for SigmaProp { )) } } + /// Arbitrary impl for ProveDlog #[cfg(feature = "arbitrary")] #[allow(clippy::unwrap_used)] diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs index 3b6c31afa..957f46354 100644 --- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs +++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cand.rs @@ -48,6 +48,19 @@ impl Cand { } } +impl std::fmt::Display for Cand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("(")?; + for (i, item) in self.items.iter().enumerate() { + if i > 0 { + f.write_str(" && ")?; + } + item.fmt(f)?; + } + f.write_str(")") + } +} + impl SigmaSerializable for Cand { fn sigma_serialize(&self, w: &mut W) -> SigmaSerializeResult { w.put_u16(self.items.len() as u16)?; diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs index 04f589586..acf0c3f9e 100644 --- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs +++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cor.rs @@ -49,6 +49,19 @@ impl Cor { } } +impl std::fmt::Display for Cor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("(")?; + for (i, item) in self.items.iter().enumerate() { + if i > 0 { + f.write_str(" || ")?; + } + item.fmt(f)?; + } + f.write_str(")") + } +} + impl SigmaSerializable for Cor { fn sigma_serialize(&self, w: &mut W) -> SigmaSerializeResult { w.put_u16(self.items.len() as u16)?; diff --git a/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs b/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs index 8db1243d6..125661d68 100644 --- a/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs +++ b/ergotree-ir/src/sigma_protocol/sigma_boolean/cthreshold.rs @@ -81,6 +81,21 @@ impl Cthreshold { } } +impl std::fmt::Display for Cthreshold { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("atLeast(")?; + f.write_str(self.k.to_string().as_str())?; + f.write_str(", (")?; + for (i, item) in self.children.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + item.fmt(f)?; + } + f.write_str(")") + } +} + impl HasStaticOpCode for Cthreshold { const OP_CODE: OpCode = OpCode::ATLEAST; } From 22ca326e43502c9933cb2c957d8f684baaa73ee1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 21 Aug 2023 11:05:47 +0300 Subject: [PATCH 30/74] set empty source span for IR nodes that can only fail at runtime due the the invalid type of args which should be eliminated by the type checking during the compilation; --- ergotree-ir/src/source_span.rs | 74 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 142e700c8..eabeb5fe6 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -92,46 +92,46 @@ impl Expr { match self { Expr::Append(op) => op.source_span, Expr::Const(_) => SourceSpan::empty(), - Expr::ConstPlaceholder(_) => todo!(), + Expr::ConstPlaceholder(_) => SourceSpan::empty(), Expr::SubstConstants(_) => todo!(), Expr::ByteArrayToLong(_) => todo!(), Expr::ByteArrayToBigInt(_) => todo!(), - Expr::LongToByteArray(_) => todo!(), - Expr::Collection(_) => todo!(), - Expr::Tuple(_) => todo!(), - Expr::CalcBlake2b256(_) => todo!(), - Expr::CalcSha256(_) => todo!(), - Expr::Context => todo!(), - Expr::Global => todo!(), + Expr::LongToByteArray(_) => SourceSpan::empty(), + Expr::Collection(_) => SourceSpan::empty(), + Expr::Tuple(_) => SourceSpan::empty(), + Expr::CalcBlake2b256(_) => SourceSpan::empty(), + Expr::CalcSha256(_) => SourceSpan::empty(), + Expr::Context => SourceSpan::empty(), + Expr::Global => SourceSpan::empty(), Expr::GlobalVars(_) => SourceSpan::empty(), - Expr::FuncValue(_) => todo!(), - Expr::Apply(_) => todo!(), + Expr::FuncValue(_) => SourceSpan::empty(), + Expr::Apply(_) => SourceSpan::empty(), Expr::MethodCall(_) => todo!(), Expr::ProperyCall(_) => todo!(), Expr::BlockValue(op) => op.source_span, Expr::ValDef(op) => op.source_span, Expr::ValUse(_) => SourceSpan::empty(), - Expr::If(_) => todo!(), + Expr::If(_) => SourceSpan::empty(), Expr::BinOp(op) => op.source_span, - Expr::And(_) => todo!(), - Expr::Or(_) => todo!(), - Expr::Xor(_) => todo!(), - Expr::Atleast(_) => todo!(), - Expr::LogicalNot(_) => todo!(), + Expr::And(_) => SourceSpan::empty(), + Expr::Or(_) => SourceSpan::empty(), + Expr::Xor(_) => SourceSpan::empty(), + Expr::Atleast(_) => SourceSpan::empty(), + Expr::LogicalNot(_) => SourceSpan::empty(), Expr::Negation(_) => todo!(), - Expr::BitInversion(_) => todo!(), + Expr::BitInversion(_) => SourceSpan::empty(), Expr::OptionGet(_) => todo!(), Expr::OptionIsDefined(_) => todo!(), Expr::OptionGetOrElse(_) => todo!(), - Expr::ExtractAmount(_) => todo!(), + Expr::ExtractAmount(_) => SourceSpan::empty(), Expr::ExtractRegisterAs(_) => todo!(), - Expr::ExtractBytes(_) => todo!(), - Expr::ExtractBytesWithNoRef(_) => todo!(), - Expr::ExtractScriptBytes(_) => todo!(), - Expr::ExtractCreationInfo(_) => todo!(), - Expr::ExtractId(_) => todo!(), + Expr::ExtractBytes(_) => SourceSpan::empty(), + Expr::ExtractBytesWithNoRef(_) => SourceSpan::empty(), + Expr::ExtractScriptBytes(_) => SourceSpan::empty(), + Expr::ExtractCreationInfo(_) => SourceSpan::empty(), + Expr::ExtractId(_) => SourceSpan::empty(), Expr::ByIndex(op) => op.source_span, - Expr::SizeOf(_) => todo!(), + Expr::SizeOf(_) => SourceSpan::empty(), Expr::Slice(_) => todo!(), Expr::Fold(_) => todo!(), Expr::Map(_) => todo!(), @@ -139,23 +139,23 @@ impl Expr { Expr::Exists(_) => todo!(), Expr::ForAll(_) => todo!(), Expr::SelectField(_) => todo!(), - Expr::BoolToSigmaProp(_) => todo!(), - Expr::Upcast(_) => todo!(), - Expr::Downcast(_) => todo!(), - Expr::CreateProveDlog(_) => todo!(), - Expr::CreateProveDhTuple(_) => todo!(), - Expr::SigmaPropBytes(_) => todo!(), - Expr::DecodePoint(_) => todo!(), - Expr::SigmaAnd(_) => todo!(), - Expr::SigmaOr(_) => todo!(), + Expr::BoolToSigmaProp(_) => SourceSpan::empty(), + Expr::Upcast(_) => SourceSpan::empty(), + Expr::Downcast(_) => SourceSpan::empty(), + Expr::CreateProveDlog(_) => SourceSpan::empty(), + Expr::CreateProveDhTuple(_) => SourceSpan::empty(), + Expr::SigmaPropBytes(_) => SourceSpan::empty(), + Expr::DecodePoint(_) => SourceSpan::empty(), + Expr::SigmaAnd(_) => SourceSpan::empty(), + Expr::SigmaOr(_) => SourceSpan::empty(), Expr::GetVar(_) => todo!(), Expr::DeserializeRegister(_) => todo!(), Expr::DeserializeContext(_) => todo!(), - Expr::MultiplyGroup(_) => todo!(), - Expr::Exponentiate(_) => todo!(), - Expr::XorOf(_) => todo!(), + Expr::MultiplyGroup(_) => SourceSpan::empty(), + Expr::Exponentiate(_) => SourceSpan::empty(), + Expr::XorOf(_) => SourceSpan::empty(), Expr::TreeLookup(_) => todo!(), - Expr::CreateAvlTree(_) => todo!(), + Expr::CreateAvlTree(_) => SourceSpan::empty(), } } } From e355048c008dee237586e72316a6e1c8d670be81 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 21 Aug 2023 14:01:40 +0300 Subject: [PATCH 31/74] add details to error messages in EvalError variants; --- ergotree-interpreter/src/eval/decode_point.rs | 5 ++-- .../src/eval/deserialize_context.rs | 6 ++--- .../src/eval/deserialize_register.rs | 27 ++++++++----------- ergotree-interpreter/src/eval/error.rs | 3 --- .../src/eval/extract_reg_as.rs | 8 +++--- ergotree-interpreter/src/eval/sbox.rs | 15 ++++++----- ergotree-ir/src/chain/ergo_box/register/id.rs | 15 +++++++++-- ergotree-ir/src/mir/expr.rs | 10 +++++++ ergotree-ir/src/pretty_printer.rs | 5 ++++ 9 files changed, 58 insertions(+), 36 deletions(-) diff --git a/ergotree-interpreter/src/eval/decode_point.rs b/ergotree-interpreter/src/eval/decode_point.rs index 61de550ed..f088e6078 100644 --- a/ergotree-interpreter/src/eval/decode_point.rs +++ b/ergotree-interpreter/src/eval/decode_point.rs @@ -14,8 +14,9 @@ impl Evaluable for DecodePoint { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { let point_bytes = self.input.eval(env, ctx)?.try_extract_into::>()?; let point: EcPoint = SigmaSerializable::sigma_parse_bytes(&point_bytes).map_err(|_| { - Misc(String::from( - "DecodePoint: Failed to parse EC point from bytes", + Misc(format!( + "DecodePoint: Failed to parse EC point from bytes {:?}", + point_bytes, )) })?; Ok(point.into()) diff --git a/ergotree-interpreter/src/eval/deserialize_context.rs b/ergotree-interpreter/src/eval/deserialize_context.rs index 49485e389..6a4e48f6e 100644 --- a/ergotree-interpreter/src/eval/deserialize_context.rs +++ b/ergotree-interpreter/src/eval/deserialize_context.rs @@ -17,14 +17,14 @@ impl Evaluable for DeserializeContext { let expected_tpe = SType::SColl(SType::SByte.into()); if c.tpe != expected_tpe { Err(EvalError::UnexpectedExpr(format!( - "DeserializeContext: expected extension value to have type {:?} got {:?}", - expected_tpe, c.tpe + "DeserializeContext: expected extension value {} with id {} to have type {:?} got {:?}", + c, self.id, expected_tpe, c.tpe ))) } else { let bytes = c.v.clone().try_extract_into::>()?; let expr = Expr::sigma_parse_bytes(bytes.as_slice())?; if expr.tpe() != self.tpe { - return Err(EvalError::UnexpectedExpr(format!("DeserializeContext: expected deserialized expr to have type {:?}, got {:?}", self.tpe, expr.tpe()))); + return Err(EvalError::UnexpectedExpr(format!("DeserializeContext: expected deserialized expr from extension value {} with id {} to have type {:?}, got {:?}", c, self.id, self.tpe, expr.tpe()))); } expr.eval(env, ctx) } diff --git a/ergotree-interpreter/src/eval/deserialize_register.rs b/ergotree-interpreter/src/eval/deserialize_register.rs index 5204316c9..10ee394a9 100644 --- a/ergotree-interpreter/src/eval/deserialize_register.rs +++ b/ergotree-interpreter/src/eval/deserialize_register.rs @@ -1,5 +1,6 @@ use std::convert::TryInto; +use ergotree_ir::chain::ergo_box::RegisterId; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::deserialize_register::DeserializeRegister; use ergotree_ir::mir::expr::Expr; @@ -14,26 +15,22 @@ use crate::eval::Evaluable; impl Evaluable for DeserializeRegister { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { - match ctx - .ctx - .self_box - .get_register(self.reg.try_into().map_err(|e| { - EvalError::RegisterIdOutOfBounds(format!( - "register index is out of bounds: {:?} ", - e - )) - })?) { + let reg_id: RegisterId = self.reg.try_into().map_err(|e| { + EvalError::RegisterIdOutOfBounds(format!("register index is out of bounds: {:?} ", e)) + })?; + match ctx.ctx.self_box.get_register(reg_id) { Ok(Some(c)) => { if c.tpe != SType::SColl(SType::SByte.into()) { Err(EvalError::UnexpectedExpr(format!( - "DeserializeRegister: expected value to have type SColl(SByte), got {:?}", - c.tpe + "DeserializeRegister: expected register {} value {} to have type SColl(SByte), got {:?}", + reg_id, c, c.tpe ))) } else { let bytes = c.v.try_extract_into::>()?; let expr = Expr::sigma_parse_bytes(bytes.as_slice())?; if expr.tpe() != self.tpe { - Err(EvalError::UnexpectedExpr(format!("DeserializeRegister: expected deserialized expr to have type {:?}, got {:?}", self.tpe, expr.tpe()))) + let pretty_expr = expr.to_string_pretty(); + Err(EvalError::UnexpectedExpr(format!("DeserializeRegister: expected register {reg_id} deserialized expr {pretty_expr} to have type {:?}, got {:?}", self.tpe, expr.tpe()))) } else { expr.eval(env, ctx) } @@ -42,15 +39,13 @@ impl Evaluable for DeserializeRegister { Ok(None) => match &self.default { Some(default_expr) => eval_default(&self.tpe, default_expr, env, ctx), None => Err(EvalError::NotFound(format!( - "DeserializeRegister: register {:?} is empty", - self.reg + "DeserializeRegister: register {reg_id} is empty" ))), }, Err(e) => match &self.default { Some(default_expr) => eval_default(&self.tpe, default_expr, env, ctx), None => Err(EvalError::NotFound(format!( - "DeserializeRegister: failed to get the register id {} with error: {e:?}", - self.reg + "DeserializeRegister: failed to get the register id {reg_id} with error: {e:?}" ))), }, } diff --git a/ergotree-interpreter/src/eval/error.rs b/ergotree-interpreter/src/eval/error.rs index ca410e829..0f4b539ed 100644 --- a/ergotree-interpreter/src/eval/error.rs +++ b/ergotree-interpreter/src/eval/error.rs @@ -58,9 +58,6 @@ pub enum EvalError { /// ErgoTree error #[error("ErgoTree error: {0}")] ErgoTreeError(#[from] ErgoTreeError), - /// Not yet implemented - #[error("evaluation is not yet implemented: {0}")] - NotImplementedYet(&'static str), /// Invalid item quantity for BoundedVec #[error("Invalid item quantity for BoundedVec: {0}")] BoundedVecError(#[from] BoundedVecOutOfBounds), diff --git a/ergotree-interpreter/src/eval/extract_reg_as.rs b/ergotree-interpreter/src/eval/extract_reg_as.rs index 6940a0b4d..656220c63 100644 --- a/ergotree-interpreter/src/eval/extract_reg_as.rs +++ b/ergotree-interpreter/src/eval/extract_reg_as.rs @@ -18,12 +18,14 @@ impl Evaluable for ExtractRegisterAs { .eval(env, ctx)? .try_extract_into::>()?; let id = self.register_id.try_into().map_err(|e| { - EvalError::RegisterIdOutOfBounds(format!("register index is out of bounds: {:?} ", e)) + EvalError::RegisterIdOutOfBounds(format!( + "register index {} is out of bounds: {:?} ", + self.register_id, e + )) })?; let reg_val_opt = ir_box.get_register(id).map_err(|e| { EvalError::NotFound(format!( - "Error getting the register id {:?} with error {e:?}", - id + "Error getting the register id {id} with error {e:?}" )) })?; Ok(Value::Opt(Box::new(reg_val_opt.map(|c| Value::from(c.v))))) diff --git a/ergotree-interpreter/src/eval/sbox.rs b/ergotree-interpreter/src/eval/sbox.rs index aa28cf416..26d130584 100644 --- a/ergotree-interpreter/src/eval/sbox.rs +++ b/ergotree-interpreter/src/eval/sbox.rs @@ -20,19 +20,20 @@ pub(crate) static GET_REG_EVAL_FN: EvalFn = |_env, _ctx, obj, args| { .get(0) .cloned() .ok_or_else(|| EvalError::NotFound("register index is missing".to_string()))? - .try_extract_into::()? - .try_into() - .map_err(|e| { - EvalError::RegisterIdOutOfBounds(format!("register index is out of bounds: {:?} ", e)) - })?; + .try_extract_into::()?; + let reg_id = reg_id.try_into().map_err(|e| { + EvalError::RegisterIdOutOfBounds(format!( + "register index {reg_id} is out of bounds: {:?} ", + e + )) + })?; Ok(Value::Opt(Box::new( obj.try_extract_into::>()? .get_register(reg_id) .map_err(|e| { EvalError::NotFound(format!( - "Error getting the register id {:?} with error {e:?}", - reg_id + "Error getting the register id {reg_id} with error {e:?}" )) })? .map(|c| Value::from(c.v)), diff --git a/ergotree-ir/src/chain/ergo_box/register/id.rs b/ergotree-ir/src/chain/ergo_box/register/id.rs index 6fefa624e..65355bdb4 100644 --- a/ergotree-ir/src/chain/ergo_box/register/id.rs +++ b/ergotree-ir/src/chain/ergo_box/register/id.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use derive_more::From; use thiserror::Error; @@ -52,8 +54,17 @@ impl TryFrom for RegisterId { } } +impl Display for RegisterId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RegisterId::MandatoryRegisterId(id) => write!(f, "{}", id), + RegisterId::NonMandatoryRegisterId(id) => write!(f, "{}", id), + } + } +} + /// Register ids that every box have (box properties exposed as registers) -#[derive(PartialEq, Eq, Debug, Clone, Copy)] +#[derive(PartialEq, Eq, Debug, Clone, Copy, derive_more::Display)] pub enum MandatoryRegisterId { /// Monetary value, in Ergo tokens R0 = 0, @@ -80,7 +91,7 @@ impl TryFrom for MandatoryRegisterId { } /// newtype for additional registers R4 - R9 -#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, derive_more::Display)] #[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "json", serde(into = "String", try_from = "String"))] #[repr(u8)] diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index d20a3fef0..54ad501e6 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -3,6 +3,8 @@ use std::convert::TryFrom; use std::convert::TryInto; +use crate::pretty_printer::PosTrackingWriter; +use crate::pretty_printer::Print; use crate::source_span::Spanned; use crate::types::stype::LiftIntoSType; use crate::types::stype::SType; @@ -328,6 +330,14 @@ impl Expr { let tree = format!("{:#?}", self); tree } + + /// Pretty prints the tree + pub fn to_string_pretty(&self) -> String { + let mut printer = PosTrackingWriter::new(); + #[allow(clippy::unwrap_used)] // it only fail due to formatting errors + let _spanned_expr = self.print(&mut printer).unwrap(); + printer.as_string() + } } impl + LiftIntoSType> From for Expr { diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 1894ffa69..af1c681ab 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -232,6 +232,11 @@ impl PosTrackingWriter { pub fn get_buf(&self) -> &str { &self.print_buf } + + /// Get printed buffer as String + pub fn as_string(self) -> String { + self.print_buf + } } impl Default for PosTrackingWriter { From 8cf9c879ce20567554c6029f93da6e86144a4ba7 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 21 Aug 2023 14:07:26 +0300 Subject: [PATCH 32/74] fix formatting; --- ergotree-interpreter/src/eval/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 651999dd5..143b024e6 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -3,11 +3,11 @@ use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; +use super::error::ExtResultEvalError; use super::Env; use super::EvalContext; use super::EvalError; use super::Evaluable; -use super::error::ExtResultEvalError; impl Evaluable for Expr { fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { From 922e2ad874a138b194eda6e69af956e85fc49044 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 21 Aug 2023 14:12:28 +0300 Subject: [PATCH 33/74] update compiler tests expected results --- ergoscript-compiler/src/mir/lower.rs | 90 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/ergoscript-compiler/src/mir/lower.rs b/ergoscript-compiler/src/mir/lower.rs index c4540679d..5ddfc8bd4 100644 --- a/ergoscript-compiler/src/mir/lower.rs +++ b/ergoscript-compiler/src/mir/lower.rs @@ -110,19 +110,25 @@ mod tests { check( "HEIGHT + HEIGHT", expect![[r#" - BinOp( - BinOp { - kind: Arith( - Plus, - ), - left: GlobalVars( - Height, - ), - right: GlobalVars( - Height, - ), - }, - )"#]], + BinOp( + Spanned { + source_span: SourceSpan { + offset: 0, + length: 0, + }, + expr: BinOp { + kind: Arith( + Plus, + ), + left: GlobalVars( + Height, + ), + right: GlobalVars( + Height, + ), + }, + }, + )"#]], ) } @@ -154,16 +160,22 @@ mod tests { "4+2", expect![[r#" BinOp( - BinOp { - kind: Arith( - Plus, - ), - left: Const( - "4: SInt", - ), - right: Const( - "2: SInt", - ), + Spanned { + source_span: SourceSpan { + offset: 0, + length: 0, + }, + expr: BinOp { + kind: Arith( + Plus, + ), + left: Const( + "4: SInt", + ), + right: Const( + "2: SInt", + ), + }, }, )"#]], ); @@ -174,19 +186,25 @@ mod tests { check( "4L+2L", expect![[r#" - BinOp( - BinOp { - kind: Arith( - Plus, - ), - left: Const( - "4: SLong", - ), - right: Const( - "2: SLong", - ), - }, - )"#]], + BinOp( + Spanned { + source_span: SourceSpan { + offset: 0, + length: 0, + }, + expr: BinOp { + kind: Arith( + Plus, + ), + left: Const( + "4: SLong", + ), + right: Const( + "2: SLong", + ), + }, + }, + )"#]], ); } } From 54412d49208a4a4f7a2033e51ff50af22d39d200 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:40:42 +0300 Subject: [PATCH 34/74] Wrap SubstConstants in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-interpreter/src/eval/subst_const.rs | 4 ++-- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 143b024e6..a8cbffbbf 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -14,7 +14,7 @@ impl Evaluable for Expr { ctx.cost_accum.add_cost_of(self)?; let res = match self { Expr::Const(c) => Ok(Value::from(c.v.clone())), - Expr::SubstConstants(op) => op.eval(env, ctx), + Expr::SubstConstants(op) => op.expr().eval(env, ctx), Expr::ByteArrayToLong(op) => op.eval(env, ctx), Expr::ByteArrayToBigInt(op) => op.eval(env, ctx), Expr::LongToByteArray(op) => op.eval(env, ctx), diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs index f70b2a1d9..ed27ceee1 100644 --- a/ergotree-interpreter/src/eval/subst_const.rs +++ b/ergotree-interpreter/src/eval/subst_const.rs @@ -135,7 +135,7 @@ mod tests { script_bytes, positions, new_values, - }); + }.into()); let x: Value = try_eval_out_wo_ctx(&subst_const).unwrap(); if let Value::Coll(CollKind::NativeColl(NativeColl::CollByte(b))) = x { @@ -182,7 +182,7 @@ mod tests { script_bytes, positions, new_values, - }); + }.into()); let x: Value = try_eval_out_wo_ctx(&subst_const).unwrap(); if let Value::Coll(CollKind::NativeColl(NativeColl::CollByte(b))) = x { diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 54ad501e6..cf4f45d69 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -93,7 +93,7 @@ pub enum Expr { /// Placeholder for a constant ConstPlaceholder(ConstantPlaceholder), /// Substitute constants in serialized ergo tree - SubstConstants(SubstConstants), + SubstConstants(Spanned), /// Convert byte array to SLong ByteArrayToLong(ByteArrayToLong), /// Convert byte array to SLong @@ -233,7 +233,7 @@ impl Expr { Expr::Append(ap) => ap.expr().tpe(), Expr::Const(v) => v.tpe.clone(), Expr::Collection(v) => v.tpe(), - Expr::SubstConstants(v) => v.tpe(), + Expr::SubstConstants(v) => v.expr().tpe(), Expr::ByteArrayToLong(v) => v.tpe(), Expr::ByteArrayToBigInt(v) => v.tpe(), Expr::LongToByteArray(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 1bc4d1bd5..11884bd59 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -225,7 +225,7 @@ impl SigmaSerializable for Expr { Expr::Append(ap) => ap.expr().sigma_serialize_w_opcode(w), Expr::Fold(op) => op.sigma_serialize_w_opcode(w), Expr::ConstPlaceholder(cp) => cp.sigma_serialize_w_opcode(w), - Expr::SubstConstants(s) => s.sigma_serialize_w_opcode(w), + Expr::SubstConstants(s) => s.expr().sigma_serialize_w_opcode(w), Expr::ByteArrayToLong(s) => s.sigma_serialize_w_opcode(w), Expr::ByteArrayToBigInt(s) => s.sigma_serialize_w_opcode(w), Expr::LongToByteArray(s) => s.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index eabeb5fe6..d73b2d84e 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -5,6 +5,7 @@ use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; +use crate::mir::subst_const::SubstConstants; use crate::mir::val_def::ValDef; /// Source position for the Expr @@ -75,6 +76,7 @@ into_expr!(BlockValue); into_expr!(ValDef); into_expr!(BinOp); into_expr!(ByIndex); +into_expr!(SubstConstants); impl From for Spanned { fn from(v: T) -> Self { @@ -93,7 +95,7 @@ impl Expr { Expr::Append(op) => op.source_span, Expr::Const(_) => SourceSpan::empty(), Expr::ConstPlaceholder(_) => SourceSpan::empty(), - Expr::SubstConstants(_) => todo!(), + Expr::SubstConstants(op) => op.source_span, Expr::ByteArrayToLong(_) => todo!(), Expr::ByteArrayToBigInt(_) => todo!(), Expr::LongToByteArray(_) => SourceSpan::empty(), From c2747adbd4debff9abb500472865b071be7cec59 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:43:27 +0300 Subject: [PATCH 35/74] Wrap ByteArrayToLong in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index a8cbffbbf..bb52cfc3c 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -15,7 +15,7 @@ impl Evaluable for Expr { let res = match self { Expr::Const(c) => Ok(Value::from(c.v.clone())), Expr::SubstConstants(op) => op.expr().eval(env, ctx), - Expr::ByteArrayToLong(op) => op.eval(env, ctx), + Expr::ByteArrayToLong(op) => op.expr().eval(env, ctx), Expr::ByteArrayToBigInt(op) => op.eval(env, ctx), Expr::LongToByteArray(op) => op.eval(env, ctx), Expr::CalcBlake2b256(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index cf4f45d69..ba6442dbc 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -95,7 +95,7 @@ pub enum Expr { /// Substitute constants in serialized ergo tree SubstConstants(Spanned), /// Convert byte array to SLong - ByteArrayToLong(ByteArrayToLong), + ByteArrayToLong(Spanned), /// Convert byte array to SLong ByteArrayToBigInt(ByteArrayToBigInt), /// Convert SLong to a byte array @@ -234,7 +234,7 @@ impl Expr { Expr::Const(v) => v.tpe.clone(), Expr::Collection(v) => v.tpe(), Expr::SubstConstants(v) => v.expr().tpe(), - Expr::ByteArrayToLong(v) => v.tpe(), + Expr::ByteArrayToLong(v) => v.expr().tpe(), Expr::ByteArrayToBigInt(v) => v.tpe(), Expr::LongToByteArray(v) => v.tpe(), Expr::ConstPlaceholder(v) => v.tpe.clone(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 11884bd59..acaacb8e5 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -226,7 +226,7 @@ impl SigmaSerializable for Expr { Expr::Fold(op) => op.sigma_serialize_w_opcode(w), Expr::ConstPlaceholder(cp) => cp.sigma_serialize_w_opcode(w), Expr::SubstConstants(s) => s.expr().sigma_serialize_w_opcode(w), - Expr::ByteArrayToLong(s) => s.sigma_serialize_w_opcode(w), + Expr::ByteArrayToLong(s) => s.expr().sigma_serialize_w_opcode(w), Expr::ByteArrayToBigInt(s) => s.sigma_serialize_w_opcode(w), Expr::LongToByteArray(s) => s.sigma_serialize_w_opcode(w), Expr::GlobalVars(op) => op.op_code().sigma_serialize(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index d73b2d84e..024792d5c 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -2,6 +2,7 @@ use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; +use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; @@ -77,6 +78,7 @@ into_expr!(ValDef); into_expr!(BinOp); into_expr!(ByIndex); into_expr!(SubstConstants); +into_expr!(ByteArrayToLong); impl From for Spanned { fn from(v: T) -> Self { @@ -96,7 +98,7 @@ impl Expr { Expr::Const(_) => SourceSpan::empty(), Expr::ConstPlaceholder(_) => SourceSpan::empty(), Expr::SubstConstants(op) => op.source_span, - Expr::ByteArrayToLong(_) => todo!(), + Expr::ByteArrayToLong(op) => op.source_span, Expr::ByteArrayToBigInt(_) => todo!(), Expr::LongToByteArray(_) => SourceSpan::empty(), Expr::Collection(_) => SourceSpan::empty(), From ae4fd0faf37f5fa417953c82c151c769362b8966 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:45:05 +0300 Subject: [PATCH 36/74] Wrap ByteArrayToBigInt in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index bb52cfc3c..c88df13b8 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -16,7 +16,7 @@ impl Evaluable for Expr { Expr::Const(c) => Ok(Value::from(c.v.clone())), Expr::SubstConstants(op) => op.expr().eval(env, ctx), Expr::ByteArrayToLong(op) => op.expr().eval(env, ctx), - Expr::ByteArrayToBigInt(op) => op.eval(env, ctx), + Expr::ByteArrayToBigInt(op) => op.expr().eval(env, ctx), Expr::LongToByteArray(op) => op.eval(env, ctx), Expr::CalcBlake2b256(op) => op.eval(env, ctx), Expr::CalcSha256(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index ba6442dbc..6e50195ef 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -97,7 +97,7 @@ pub enum Expr { /// Convert byte array to SLong ByteArrayToLong(Spanned), /// Convert byte array to SLong - ByteArrayToBigInt(ByteArrayToBigInt), + ByteArrayToBigInt(Spanned), /// Convert SLong to a byte array LongToByteArray(LongToByteArray), /// Collection declaration (array of expressions of the same type) @@ -235,7 +235,7 @@ impl Expr { Expr::Collection(v) => v.tpe(), Expr::SubstConstants(v) => v.expr().tpe(), Expr::ByteArrayToLong(v) => v.expr().tpe(), - Expr::ByteArrayToBigInt(v) => v.tpe(), + Expr::ByteArrayToBigInt(v) => v.expr().tpe(), Expr::LongToByteArray(v) => v.tpe(), Expr::ConstPlaceholder(v) => v.tpe.clone(), Expr::CalcBlake2b256(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index acaacb8e5..0645508a8 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -227,7 +227,7 @@ impl SigmaSerializable for Expr { Expr::ConstPlaceholder(cp) => cp.sigma_serialize_w_opcode(w), Expr::SubstConstants(s) => s.expr().sigma_serialize_w_opcode(w), Expr::ByteArrayToLong(s) => s.expr().sigma_serialize_w_opcode(w), - Expr::ByteArrayToBigInt(s) => s.sigma_serialize_w_opcode(w), + Expr::ByteArrayToBigInt(s) => s.expr().sigma_serialize_w_opcode(w), Expr::LongToByteArray(s) => s.sigma_serialize_w_opcode(w), Expr::GlobalVars(op) => op.op_code().sigma_serialize(w), Expr::MethodCall(mc) => mc.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 024792d5c..9738794cf 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -2,6 +2,7 @@ use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; +use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; @@ -79,6 +80,7 @@ into_expr!(BinOp); into_expr!(ByIndex); into_expr!(SubstConstants); into_expr!(ByteArrayToLong); +into_expr!(ByteArrayToBigInt); impl From for Spanned { fn from(v: T) -> Self { @@ -99,7 +101,7 @@ impl Expr { Expr::ConstPlaceholder(_) => SourceSpan::empty(), Expr::SubstConstants(op) => op.source_span, Expr::ByteArrayToLong(op) => op.source_span, - Expr::ByteArrayToBigInt(_) => todo!(), + Expr::ByteArrayToBigInt(op) => op.source_span, Expr::LongToByteArray(_) => SourceSpan::empty(), Expr::Collection(_) => SourceSpan::empty(), Expr::Tuple(_) => SourceSpan::empty(), From afd73c6725513f1ef96550d2c8df62da98d29cd6 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:47:23 +0300 Subject: [PATCH 37/74] wrap MethodCall in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-interpreter/src/eval/scoll.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 4 ++-- ergotree-ir/src/source_span.rs | 4 +++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index c88df13b8..2b4707dfe 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -23,7 +23,7 @@ impl Evaluable for Expr { Expr::Fold(op) => op.eval(env, ctx), Expr::ExtractRegisterAs(op) => op.eval(env, ctx), Expr::GlobalVars(op) => op.eval(env, ctx), - Expr::MethodCall(op) => op.eval(env, ctx), + Expr::MethodCall(op) => op.expr().eval(env, ctx), Expr::ProperyCall(op) => op.eval(env, ctx), Expr::BinOp(op) => op.expr().eval(env, ctx), Expr::Global => Ok(Value::Global), diff --git a/ergotree-interpreter/src/eval/scoll.rs b/ergotree-interpreter/src/eval/scoll.rs index d4f5eea27..4e1f0c625 100644 --- a/ergotree-interpreter/src/eval/scoll.rs +++ b/ergotree-interpreter/src/eval/scoll.rs @@ -60,7 +60,7 @@ pub(crate) static FLATMAP_EVAL_FN: EvalFn = |env, ctx, obj, args| { "unsupported lambda in flatMap: allowed usage `xs.flatMap(x => x.property)".to_string(); match &*lambda.body { Expr::MethodCall(mc) => { - if !mc.args.is_empty() { + if !mc.expr().args.is_empty() { return Err(EvalError::UnexpectedValue(unsupported_msg)); } } diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 6e50195ef..bfa6f35e0 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -120,7 +120,7 @@ pub enum Expr { /// Function application Apply(Apply), /// Method call - MethodCall(MethodCall), + MethodCall(Spanned), /// Property call ProperyCall(PropertyCall), /// Block (statements, followed by an expression) @@ -245,7 +245,7 @@ impl Expr { Expr::GlobalVars(v) => v.tpe(), Expr::FuncValue(v) => v.tpe(), Expr::Apply(v) => v.tpe(), - Expr::MethodCall(v) => v.tpe(), + Expr::MethodCall(v) => v.expr().tpe(), Expr::ProperyCall(v) => v.tpe(), Expr::BlockValue(v) => v.expr().tpe(), Expr::ValDef(v) => v.expr().tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 0645508a8..16dcad749 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -113,7 +113,7 @@ impl Expr { OpCode::GROUP_GENERATOR => Ok(Expr::GlobalVars(GlobalVars::GroupGenerator)), OpCode::GLOBAL => Ok(Expr::Global), OpCode::PROPERTY_CALL => Ok(Expr::ProperyCall(PropertyCall::sigma_parse(r)?)), - OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?)), + OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?.into())), OpCode::CONTEXT => Ok(Expr::Context), OptionGet::OP_CODE => Ok(OptionGet::sigma_parse(r)?.into()), OptionIsDefined::OP_CODE => Ok(OptionIsDefined::sigma_parse(r)?.into()), @@ -230,7 +230,7 @@ impl SigmaSerializable for Expr { Expr::ByteArrayToBigInt(s) => s.expr().sigma_serialize_w_opcode(w), Expr::LongToByteArray(s) => s.sigma_serialize_w_opcode(w), Expr::GlobalVars(op) => op.op_code().sigma_serialize(w), - Expr::MethodCall(mc) => mc.sigma_serialize_w_opcode(w), + Expr::MethodCall(mc) => mc.expr().sigma_serialize_w_opcode(w), Expr::ProperyCall(pc) => pc.sigma_serialize_w_opcode(w), Expr::Global => OpCode::GLOBAL.sigma_serialize(w), Expr::Context => OpCode::CONTEXT.sigma_serialize(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 9738794cf..0760fcf7e 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -7,6 +7,7 @@ use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; +use crate::mir::method_call::MethodCall; use crate::mir::subst_const::SubstConstants; use crate::mir::val_def::ValDef; @@ -81,6 +82,7 @@ into_expr!(ByIndex); into_expr!(SubstConstants); into_expr!(ByteArrayToLong); into_expr!(ByteArrayToBigInt); +into_expr!(MethodCall); impl From for Spanned { fn from(v: T) -> Self { @@ -112,7 +114,7 @@ impl Expr { Expr::GlobalVars(_) => SourceSpan::empty(), Expr::FuncValue(_) => SourceSpan::empty(), Expr::Apply(_) => SourceSpan::empty(), - Expr::MethodCall(_) => todo!(), + Expr::MethodCall(op) => op.source_span, Expr::ProperyCall(_) => todo!(), Expr::BlockValue(op) => op.source_span, Expr::ValDef(op) => op.source_span, From 7ff21c0c03d66fdcafd9348eed3e19e2916460d3 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:49:43 +0300 Subject: [PATCH 38/74] wrap PropertyCall in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 6 ++++-- ergotree-ir/src/serialization/property_call.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 2b4707dfe..7edd3dfc5 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -24,7 +24,7 @@ impl Evaluable for Expr { Expr::ExtractRegisterAs(op) => op.eval(env, ctx), Expr::GlobalVars(op) => op.eval(env, ctx), Expr::MethodCall(op) => op.expr().eval(env, ctx), - Expr::ProperyCall(op) => op.eval(env, ctx), + Expr::PropertyCall(op) => op.expr().eval(env, ctx), Expr::BinOp(op) => op.expr().eval(env, ctx), Expr::Global => Ok(Value::Global), Expr::Context => Ok(Value::Context), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index bfa6f35e0..e312db389 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -122,7 +122,7 @@ pub enum Expr { /// Method call MethodCall(Spanned), /// Property call - ProperyCall(PropertyCall), + PropertyCall(Spanned), /// Block (statements, followed by an expression) BlockValue(Spanned), /// let-bound expression @@ -246,7 +246,7 @@ impl Expr { Expr::FuncValue(v) => v.tpe(), Expr::Apply(v) => v.tpe(), Expr::MethodCall(v) => v.expr().tpe(), - Expr::ProperyCall(v) => v.tpe(), + Expr::PropertyCall(v) => v.expr().tpe(), Expr::BlockValue(v) => v.expr().tpe(), Expr::ValDef(v) => v.expr().tpe(), Expr::ValUse(v) => v.tpe.clone(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 16dcad749..ef124873e 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -112,7 +112,9 @@ impl Expr { OpCode::MINER_PUBKEY => Ok(Expr::GlobalVars(GlobalVars::MinerPubKey)), OpCode::GROUP_GENERATOR => Ok(Expr::GlobalVars(GlobalVars::GroupGenerator)), OpCode::GLOBAL => Ok(Expr::Global), - OpCode::PROPERTY_CALL => Ok(Expr::ProperyCall(PropertyCall::sigma_parse(r)?)), + OpCode::PROPERTY_CALL => { + Ok(Expr::PropertyCall(PropertyCall::sigma_parse(r)?.into())) + } OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?.into())), OpCode::CONTEXT => Ok(Expr::Context), OptionGet::OP_CODE => Ok(OptionGet::sigma_parse(r)?.into()), @@ -231,7 +233,7 @@ impl SigmaSerializable for Expr { Expr::LongToByteArray(s) => s.sigma_serialize_w_opcode(w), Expr::GlobalVars(op) => op.op_code().sigma_serialize(w), Expr::MethodCall(mc) => mc.expr().sigma_serialize_w_opcode(w), - Expr::ProperyCall(pc) => pc.sigma_serialize_w_opcode(w), + Expr::PropertyCall(pc) => pc.expr().sigma_serialize_w_opcode(w), Expr::Global => OpCode::GLOBAL.sigma_serialize(w), Expr::Context => OpCode::CONTEXT.sigma_serialize(w), Expr::OptionGet(v) => v.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/serialization/property_call.rs b/ergotree-ir/src/serialization/property_call.rs index 9551de5ac..1a33d86c3 100644 --- a/ergotree-ir/src/serialization/property_call.rs +++ b/ergotree-ir/src/serialization/property_call.rs @@ -40,7 +40,7 @@ mod tests { #[test] fn ser_roundtrip_property() { let mc = PropertyCall::new(Expr::Context, scontext::DATA_INPUTS_PROPERTY.clone()).unwrap(); - let expr = Expr::ProperyCall(mc); + let expr = Expr::PropertyCall(mc.into()); assert_eq![sigma_serialize_roundtrip(&expr), expr]; } } diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 0760fcf7e..08a968020 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -8,6 +8,7 @@ use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; use crate::mir::method_call::MethodCall; +use crate::mir::property_call::PropertyCall; use crate::mir::subst_const::SubstConstants; use crate::mir::val_def::ValDef; @@ -83,6 +84,7 @@ into_expr!(SubstConstants); into_expr!(ByteArrayToLong); into_expr!(ByteArrayToBigInt); into_expr!(MethodCall); +into_expr!(PropertyCall); impl From for Spanned { fn from(v: T) -> Self { @@ -115,7 +117,7 @@ impl Expr { Expr::FuncValue(_) => SourceSpan::empty(), Expr::Apply(_) => SourceSpan::empty(), Expr::MethodCall(op) => op.source_span, - Expr::ProperyCall(_) => todo!(), + Expr::PropertyCall(op) => op.source_span, Expr::BlockValue(op) => op.source_span, Expr::ValDef(op) => op.source_span, Expr::ValUse(_) => SourceSpan::empty(), From 47960ba23c001003a0163656c47f589adf3afab4 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:53:40 +0300 Subject: [PATCH 39/74] wrap Negation in Spanned --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 +- ergotree-ir/src/pretty_printer.rs | 60 ++++++++++++++++++++++++++- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +- 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 7edd3dfc5..1ab8e4ce7 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -66,7 +66,7 @@ impl Evaluable for Expr { Expr::SigmaPropBytes(op) => op.eval(env, ctx), Expr::OptionIsDefined(op) => op.eval(env, ctx), Expr::OptionGetOrElse(op) => op.eval(env, ctx), - Expr::Negation(op) => op.eval(env, ctx), + Expr::Negation(op) => op.expr().eval(env, ctx), Expr::BitInversion(op) => op.eval(env, ctx), Expr::ForAll(op) => op.eval(env, ctx), Expr::Tuple(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index e312db389..4893a27ac 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -144,7 +144,7 @@ pub enum Expr { /// LogicalNot LogicalNot(LogicalNot), /// Negation on numeric type - Negation(Negation), + Negation(Spanned), /// Bit inversion on numeric type BitInversion(BitInversion), /// Option.get method @@ -279,7 +279,7 @@ impl Expr { Expr::SigmaPropBytes(v) => v.tpe(), Expr::OptionIsDefined(v) => v.tpe(), Expr::OptionGetOrElse(v) => v.tpe(), - Expr::Negation(v) => v.tpe(), + Expr::Negation(v) => v.expr().tpe(), Expr::BitInversion(v) => v.tpe(), Expr::ForAll(v) => v.tpe(), Expr::Tuple(v) => v.tpe(), diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index af1c681ab..9fb6caeac 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -153,6 +153,7 @@ impl Print for ByIndex { } } +#[allow(clippy::todo)] #[allow(clippy::panic)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { @@ -165,7 +166,64 @@ impl Print for Expr { Expr::BinOp(v) => v.expr().print(w), Expr::GlobalVars(v) => v.print(w), Expr::ByIndex(v) => v.expr().print(w), - e => panic!("Not implemented: {:?}", e), + Expr::ConstPlaceholder(_) => todo!(), + Expr::SubstConstants(_) => todo!(), + Expr::ByteArrayToLong(_) => todo!(), + Expr::ByteArrayToBigInt(_) => todo!(), + Expr::LongToByteArray(_) => todo!(), + Expr::Collection(_) => todo!(), + Expr::Tuple(_) => todo!(), + Expr::CalcBlake2b256(_) => todo!(), + Expr::CalcSha256(_) => todo!(), + Expr::Context => todo!(), + Expr::Global => todo!(), + Expr::FuncValue(_) => todo!(), + Expr::Apply(_) => todo!(), + Expr::MethodCall(_) => todo!(), + Expr::PropertyCall(_) => todo!(), + Expr::If(_) => todo!(), + Expr::And(_) => todo!(), + Expr::Or(_) => todo!(), + Expr::Xor(_) => todo!(), + Expr::Atleast(_) => todo!(), + Expr::LogicalNot(_) => todo!(), + Expr::Negation(_) => todo!(), + Expr::BitInversion(_) => todo!(), + Expr::OptionGet(_) => todo!(), + Expr::OptionIsDefined(_) => todo!(), + Expr::OptionGetOrElse(_) => todo!(), + Expr::ExtractAmount(_) => todo!(), + Expr::ExtractRegisterAs(_) => todo!(), + Expr::ExtractBytes(_) => todo!(), + Expr::ExtractBytesWithNoRef(_) => todo!(), + Expr::ExtractScriptBytes(_) => todo!(), + Expr::ExtractCreationInfo(_) => todo!(), + Expr::ExtractId(_) => todo!(), + Expr::SizeOf(_) => todo!(), + Expr::Slice(_) => todo!(), + Expr::Fold(_) => todo!(), + Expr::Map(_) => todo!(), + Expr::Filter(_) => todo!(), + Expr::Exists(_) => todo!(), + Expr::ForAll(_) => todo!(), + Expr::SelectField(_) => todo!(), + Expr::BoolToSigmaProp(_) => todo!(), + Expr::Upcast(_) => todo!(), + Expr::Downcast(_) => todo!(), + Expr::CreateProveDlog(_) => todo!(), + Expr::CreateProveDhTuple(_) => todo!(), + Expr::SigmaPropBytes(_) => todo!(), + Expr::DecodePoint(_) => todo!(), + Expr::SigmaAnd(_) => todo!(), + Expr::SigmaOr(_) => todo!(), + Expr::GetVar(_) => todo!(), + Expr::DeserializeRegister(_) => todo!(), + Expr::DeserializeContext(_) => todo!(), + Expr::MultiplyGroup(_) => todo!(), + Expr::Exponentiate(_) => todo!(), + Expr::XorOf(_) => todo!(), + Expr::TreeLookup(_) => todo!(), + Expr::CreateAvlTree(_) => todo!(), } } } diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index ef124873e..16ac17c01 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -278,7 +278,7 @@ impl SigmaSerializable for Expr { Expr::SigmaPropBytes(op) => op.sigma_serialize_w_opcode(w), Expr::OptionIsDefined(op) => op.sigma_serialize_w_opcode(w), Expr::OptionGetOrElse(op) => op.sigma_serialize_w_opcode(w), - Expr::Negation(op) => op.sigma_serialize_w_opcode(w), + Expr::Negation(op) => op.expr().sigma_serialize_w_opcode(w), Expr::BitInversion(op) => op.sigma_serialize_w_opcode(w), Expr::ForAll(op) => op.sigma_serialize_w_opcode(w), Expr::Tuple(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 08a968020..16c2e84ff 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,5 +1,6 @@ //! Source position for an IR node in the source code +use crate::mir::negation::Negation; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; @@ -85,6 +86,7 @@ into_expr!(ByteArrayToLong); into_expr!(ByteArrayToBigInt); into_expr!(MethodCall); into_expr!(PropertyCall); +into_expr!(Negation); impl From for Spanned { fn from(v: T) -> Self { @@ -128,7 +130,7 @@ impl Expr { Expr::Xor(_) => SourceSpan::empty(), Expr::Atleast(_) => SourceSpan::empty(), Expr::LogicalNot(_) => SourceSpan::empty(), - Expr::Negation(_) => todo!(), + Expr::Negation(op) => op.source_span, Expr::BitInversion(_) => SourceSpan::empty(), Expr::OptionGet(_) => todo!(), Expr::OptionIsDefined(_) => todo!(), From e9e24e16c5411078ac885705ed188df531b35817 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:56:07 +0300 Subject: [PATCH 40/74] wrap OptionGet in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 1ab8e4ce7..045ce376e 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -28,7 +28,7 @@ impl Evaluable for Expr { Expr::BinOp(op) => op.expr().eval(env, ctx), Expr::Global => Ok(Value::Global), Expr::Context => Ok(Value::Context), - Expr::OptionGet(v) => v.eval(env, ctx), + Expr::OptionGet(v) => v.expr().eval(env, ctx), Expr::Apply(op) => op.eval(env, ctx), Expr::FuncValue(op) => op.eval(env, ctx), Expr::ValUse(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 4893a27ac..bbe2a0fa4 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -148,7 +148,7 @@ pub enum Expr { /// Bit inversion on numeric type BitInversion(BitInversion), /// Option.get method - OptionGet(OptionGet), + OptionGet(Spanned), /// Option.isDefined method OptionIsDefined(OptionIsDefined), /// Returns the option's value if the option is nonempty, otherwise return the result of evaluating `default`. @@ -251,7 +251,7 @@ impl Expr { Expr::ValDef(v) => v.expr().tpe(), Expr::ValUse(v) => v.tpe.clone(), Expr::BinOp(v) => v.expr().tpe(), - Expr::OptionGet(v) => v.tpe(), + Expr::OptionGet(v) => v.expr().tpe(), Expr::ExtractRegisterAs(v) => v.tpe(), Expr::Fold(v) => v.tpe(), Expr::SelectField(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 16ac17c01..943782a44 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -236,7 +236,7 @@ impl SigmaSerializable for Expr { Expr::PropertyCall(pc) => pc.expr().sigma_serialize_w_opcode(w), Expr::Global => OpCode::GLOBAL.sigma_serialize(w), Expr::Context => OpCode::CONTEXT.sigma_serialize(w), - Expr::OptionGet(v) => v.sigma_serialize_w_opcode(w), + Expr::OptionGet(v) => v.expr().sigma_serialize_w_opcode(w), Expr::ExtractRegisterAs(v) => v.sigma_serialize_w_opcode(w), Expr::BinOp(op) => { op.expr().op_code().sigma_serialize(w)?; diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 16c2e84ff..996deef07 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,6 +1,5 @@ //! Source position for an IR node in the source code -use crate::mir::negation::Negation; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; @@ -9,6 +8,8 @@ use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; use crate::mir::method_call::MethodCall; +use crate::mir::negation::Negation; +use crate::mir::option_get::OptionGet; use crate::mir::property_call::PropertyCall; use crate::mir::subst_const::SubstConstants; use crate::mir::val_def::ValDef; @@ -87,6 +88,7 @@ into_expr!(ByteArrayToBigInt); into_expr!(MethodCall); into_expr!(PropertyCall); into_expr!(Negation); +into_expr!(OptionGet); impl From for Spanned { fn from(v: T) -> Self { @@ -132,7 +134,7 @@ impl Expr { Expr::LogicalNot(_) => SourceSpan::empty(), Expr::Negation(op) => op.source_span, Expr::BitInversion(_) => SourceSpan::empty(), - Expr::OptionGet(_) => todo!(), + Expr::OptionGet(op) => op.source_span, Expr::OptionIsDefined(_) => todo!(), Expr::OptionGetOrElse(_) => todo!(), Expr::ExtractAmount(_) => SourceSpan::empty(), From d8b4384a304e4f5356c597c0c724aa386319a34c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 12:58:26 +0300 Subject: [PATCH 41/74] wrap OptionIsDefined in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 045ce376e..fd3b4279a 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -64,7 +64,7 @@ impl Evaluable for Expr { Expr::Exists(op) => op.eval(env, ctx), Expr::ExtractId(op) => op.eval(env, ctx), Expr::SigmaPropBytes(op) => op.eval(env, ctx), - Expr::OptionIsDefined(op) => op.eval(env, ctx), + Expr::OptionIsDefined(op) => op.expr().eval(env, ctx), Expr::OptionGetOrElse(op) => op.eval(env, ctx), Expr::Negation(op) => op.expr().eval(env, ctx), Expr::BitInversion(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index bbe2a0fa4..44e9c875d 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -150,7 +150,7 @@ pub enum Expr { /// Option.get method OptionGet(Spanned), /// Option.isDefined method - OptionIsDefined(OptionIsDefined), + OptionIsDefined(Spanned), /// Returns the option's value if the option is nonempty, otherwise return the result of evaluating `default`. OptionGetOrElse(OptionGetOrElse), /// Box monetary value @@ -277,7 +277,7 @@ impl Expr { Expr::Exists(v) => v.tpe(), Expr::ExtractId(v) => v.tpe(), Expr::SigmaPropBytes(v) => v.tpe(), - Expr::OptionIsDefined(v) => v.tpe(), + Expr::OptionIsDefined(v) => v.expr().tpe(), Expr::OptionGetOrElse(v) => v.tpe(), Expr::Negation(v) => v.expr().tpe(), Expr::BitInversion(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 943782a44..17dc84b12 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -276,7 +276,7 @@ impl SigmaSerializable for Expr { Expr::Exists(op) => op.sigma_serialize_w_opcode(w), Expr::ExtractId(op) => op.sigma_serialize_w_opcode(w), Expr::SigmaPropBytes(op) => op.sigma_serialize_w_opcode(w), - Expr::OptionIsDefined(op) => op.sigma_serialize_w_opcode(w), + Expr::OptionIsDefined(op) => op.expr().sigma_serialize_w_opcode(w), Expr::OptionGetOrElse(op) => op.sigma_serialize_w_opcode(w), Expr::Negation(op) => op.expr().sigma_serialize_w_opcode(w), Expr::BitInversion(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 996deef07..3477a2224 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -10,6 +10,7 @@ use crate::mir::expr::Expr; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; +use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; use crate::mir::subst_const::SubstConstants; use crate::mir::val_def::ValDef; @@ -89,6 +90,7 @@ into_expr!(MethodCall); into_expr!(PropertyCall); into_expr!(Negation); into_expr!(OptionGet); +into_expr!(OptionIsDefined); impl From for Spanned { fn from(v: T) -> Self { @@ -135,7 +137,7 @@ impl Expr { Expr::Negation(op) => op.source_span, Expr::BitInversion(_) => SourceSpan::empty(), Expr::OptionGet(op) => op.source_span, - Expr::OptionIsDefined(_) => todo!(), + Expr::OptionIsDefined(op) => op.source_span, Expr::OptionGetOrElse(_) => todo!(), Expr::ExtractAmount(_) => SourceSpan::empty(), Expr::ExtractRegisterAs(_) => todo!(), From b0ef00f405045d52a1b0370ded73f320a0babcdb Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 13:00:14 +0300 Subject: [PATCH 42/74] wrap OptionGetOrElse in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index fd3b4279a..59390fedc 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -65,7 +65,7 @@ impl Evaluable for Expr { Expr::ExtractId(op) => op.eval(env, ctx), Expr::SigmaPropBytes(op) => op.eval(env, ctx), Expr::OptionIsDefined(op) => op.expr().eval(env, ctx), - Expr::OptionGetOrElse(op) => op.eval(env, ctx), + Expr::OptionGetOrElse(op) => op.expr().eval(env, ctx), Expr::Negation(op) => op.expr().eval(env, ctx), Expr::BitInversion(op) => op.eval(env, ctx), Expr::ForAll(op) => op.eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 44e9c875d..da87371c9 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -152,7 +152,7 @@ pub enum Expr { /// Option.isDefined method OptionIsDefined(Spanned), /// Returns the option's value if the option is nonempty, otherwise return the result of evaluating `default`. - OptionGetOrElse(OptionGetOrElse), + OptionGetOrElse(Spanned), /// Box monetary value ExtractAmount(ExtractAmount), /// Extract register's value (box.RX properties) @@ -278,7 +278,7 @@ impl Expr { Expr::ExtractId(v) => v.tpe(), Expr::SigmaPropBytes(v) => v.tpe(), Expr::OptionIsDefined(v) => v.expr().tpe(), - Expr::OptionGetOrElse(v) => v.tpe(), + Expr::OptionGetOrElse(v) => v.expr().tpe(), Expr::Negation(v) => v.expr().tpe(), Expr::BitInversion(v) => v.tpe(), Expr::ForAll(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 17dc84b12..4b59e6c13 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -277,7 +277,7 @@ impl SigmaSerializable for Expr { Expr::ExtractId(op) => op.sigma_serialize_w_opcode(w), Expr::SigmaPropBytes(op) => op.sigma_serialize_w_opcode(w), Expr::OptionIsDefined(op) => op.expr().sigma_serialize_w_opcode(w), - Expr::OptionGetOrElse(op) => op.sigma_serialize_w_opcode(w), + Expr::OptionGetOrElse(op) => op.expr().sigma_serialize_w_opcode(w), Expr::Negation(op) => op.expr().sigma_serialize_w_opcode(w), Expr::BitInversion(op) => op.sigma_serialize_w_opcode(w), Expr::ForAll(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 3477a2224..a4b220e5a 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -10,6 +10,7 @@ use crate::mir::expr::Expr; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; +use crate::mir::option_get_or_else::OptionGetOrElse; use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; use crate::mir::subst_const::SubstConstants; @@ -91,6 +92,7 @@ into_expr!(PropertyCall); into_expr!(Negation); into_expr!(OptionGet); into_expr!(OptionIsDefined); +into_expr!(OptionGetOrElse); impl From for Spanned { fn from(v: T) -> Self { @@ -138,7 +140,7 @@ impl Expr { Expr::BitInversion(_) => SourceSpan::empty(), Expr::OptionGet(op) => op.source_span, Expr::OptionIsDefined(op) => op.source_span, - Expr::OptionGetOrElse(_) => todo!(), + Expr::OptionGetOrElse(op) => op.source_span, Expr::ExtractAmount(_) => SourceSpan::empty(), Expr::ExtractRegisterAs(_) => todo!(), Expr::ExtractBytes(_) => SourceSpan::empty(), From cc905f5f1270cc1157c78b36eedd0bfae4b5e908 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 13:02:59 +0300 Subject: [PATCH 43/74] wrap ExtractRegisterAs in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 2 +- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index 59390fedc..a268e2881 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -21,7 +21,7 @@ impl Evaluable for Expr { Expr::CalcBlake2b256(op) => op.eval(env, ctx), Expr::CalcSha256(op) => op.eval(env, ctx), Expr::Fold(op) => op.eval(env, ctx), - Expr::ExtractRegisterAs(op) => op.eval(env, ctx), + Expr::ExtractRegisterAs(op) => op.expr().eval(env, ctx), Expr::GlobalVars(op) => op.eval(env, ctx), Expr::MethodCall(op) => op.expr().eval(env, ctx), Expr::PropertyCall(op) => op.expr().eval(env, ctx), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index da87371c9..2227c8bda 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -156,7 +156,7 @@ pub enum Expr { /// Box monetary value ExtractAmount(ExtractAmount), /// Extract register's value (box.RX properties) - ExtractRegisterAs(ExtractRegisterAs), + ExtractRegisterAs(Spanned), /// Extract serialized box bytes ExtractBytes(ExtractBytes), /// Extract serialized box bytes excluding transaction_id & index @@ -252,7 +252,7 @@ impl Expr { Expr::ValUse(v) => v.tpe.clone(), Expr::BinOp(v) => v.expr().tpe(), Expr::OptionGet(v) => v.expr().tpe(), - Expr::ExtractRegisterAs(v) => v.tpe(), + Expr::ExtractRegisterAs(v) => v.expr().tpe(), Expr::Fold(v) => v.tpe(), Expr::SelectField(v) => v.tpe(), Expr::ExtractAmount(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 4b59e6c13..084cdccea 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -237,7 +237,7 @@ impl SigmaSerializable for Expr { Expr::Global => OpCode::GLOBAL.sigma_serialize(w), Expr::Context => OpCode::CONTEXT.sigma_serialize(w), Expr::OptionGet(v) => v.expr().sigma_serialize_w_opcode(w), - Expr::ExtractRegisterAs(v) => v.sigma_serialize_w_opcode(w), + Expr::ExtractRegisterAs(v) => v.expr().sigma_serialize_w_opcode(w), Expr::BinOp(op) => { op.expr().op_code().sigma_serialize(w)?; bin_op_sigma_serialize(op.expr(), w) diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index a4b220e5a..a74867e67 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -7,6 +7,7 @@ use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::expr::Expr; +use crate::mir::extract_reg_as::ExtractRegisterAs; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; @@ -93,6 +94,7 @@ into_expr!(Negation); into_expr!(OptionGet); into_expr!(OptionIsDefined); into_expr!(OptionGetOrElse); +into_expr!(ExtractRegisterAs); impl From for Spanned { fn from(v: T) -> Self { @@ -142,7 +144,7 @@ impl Expr { Expr::OptionIsDefined(op) => op.source_span, Expr::OptionGetOrElse(op) => op.source_span, Expr::ExtractAmount(_) => SourceSpan::empty(), - Expr::ExtractRegisterAs(_) => todo!(), + Expr::ExtractRegisterAs(op) => op.source_span, Expr::ExtractBytes(_) => SourceSpan::empty(), Expr::ExtractBytesWithNoRef(_) => SourceSpan::empty(), Expr::ExtractScriptBytes(_) => SourceSpan::empty(), From a2f2a6cb4d369d867ebbb9ebe9181fac5e729d60 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 13:17:12 +0300 Subject: [PATCH 44/74] wrap Slice in Spanned; --- ergotree-interpreter/src/eval/expr.rs | 7 +++++++ ergotree-ir/src/chain/address.rs | 18 ++++++++++++------ ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ergotree-interpreter/src/eval/expr.rs b/ergotree-interpreter/src/eval/expr.rs index a268e2881..ebbe93f66 100644 --- a/ergotree-interpreter/src/eval/expr.rs +++ b/ergotree-interpreter/src/eval/expr.rs @@ -2,6 +2,7 @@ use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::value::Value; +use ergotree_ir::source_span::Spanned; use super::error::ExtResultEvalError; use super::Env; @@ -87,3 +88,9 @@ impl Evaluable for Expr { res.enrich_err(self.span(), env.clone()) } } + +impl Evaluable for Spanned { + fn eval(&self, env: &mut Env, ctx: &mut EvalContext) -> Result { + self.expr.eval(env, ctx) + } +} diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index 8fc6c3e4b..c07c1c153 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -122,7 +122,10 @@ impl Address { { if let ( Relation(RelationOp::Eq), - Expr::Slice(Slice { input, from, until }), + Expr::Slice(Spanned { + expr: Slice { input, from, until }, + source_span: _, + }), Expr::Const(Constant { v, .. }), ) = (kind, *left, *right) { @@ -214,11 +217,14 @@ impl Address { let hash_expr = Expr::CalcBlake2b256(CalcBlake2b256 { input: Box::new(get_var_expr), }); - let slice_expr = Expr::Slice(Slice { - input: Box::new(hash_expr), - from: Box::new(0i32.into()), - until: Box::new(24i32.into()), - }); + let slice_expr = Expr::Slice( + Slice { + input: Box::new(hash_expr), + from: Box::new(0i32.into()), + until: Box::new(24i32.into()), + } + .into(), + ); let hash_equals = Expr::BinOp( BinOp { kind: Relation(RelationOp::Eq), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 2227c8bda..6d8306cec 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -173,7 +173,7 @@ pub enum Expr { /// Collection size SizeOf(SizeOf), /// Collection slice - Slice(Slice), + Slice(Spanned), /// Collection fold op Fold(Fold), /// Collection map op @@ -270,7 +270,7 @@ impl Expr { Expr::ByIndex(v) => v.expr().tpe(), Expr::ExtractScriptBytes(v) => v.tpe(), Expr::SizeOf(v) => v.tpe(), - Expr::Slice(v) => v.tpe(), + Expr::Slice(v) => v.expr().tpe(), Expr::CreateProveDlog(v) => v.tpe(), Expr::CreateProveDhTuple(v) => v.tpe(), Expr::ExtractCreationInfo(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 084cdccea..d6de39343 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -269,7 +269,7 @@ impl SigmaSerializable for Expr { Expr::ByIndex(op) => op.expr().sigma_serialize_w_opcode(w), Expr::ExtractScriptBytes(op) => op.sigma_serialize_w_opcode(w), Expr::SizeOf(op) => op.sigma_serialize_w_opcode(w), - Expr::Slice(op) => op.sigma_serialize_w_opcode(w), + Expr::Slice(op) => op.expr().sigma_serialize_w_opcode(w), Expr::CreateProveDlog(op) => op.sigma_serialize_w_opcode(w), Expr::CreateProveDhTuple(op) => op.sigma_serialize_w_opcode(w), Expr::ExtractCreationInfo(op) => op.sigma_serialize_w_opcode(w), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index a74867e67..2c8edf962 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -6,6 +6,7 @@ use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; +use crate::mir::coll_slice::Slice; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; use crate::mir::method_call::MethodCall; @@ -95,6 +96,7 @@ into_expr!(OptionGet); into_expr!(OptionIsDefined); into_expr!(OptionGetOrElse); into_expr!(ExtractRegisterAs); +into_expr!(Slice); impl From for Spanned { fn from(v: T) -> Self { @@ -152,7 +154,7 @@ impl Expr { Expr::ExtractId(_) => SourceSpan::empty(), Expr::ByIndex(op) => op.source_span, Expr::SizeOf(_) => SourceSpan::empty(), - Expr::Slice(_) => todo!(), + Expr::Slice(op) => op.source_span, Expr::Fold(_) => todo!(), Expr::Map(_) => todo!(), Expr::Filter(_) => todo!(), From 984dbe6d5d5a87dec8584377c92b0779253bb782 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 14:29:54 +0300 Subject: [PATCH 45/74] wrap Fold in Spanned; --- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 19 ++++++++++++++++++- ergotree-ir/src/source_span.rs | 4 +++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 6d8306cec..174ef6c95 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -175,7 +175,7 @@ pub enum Expr { /// Collection slice Slice(Spanned), /// Collection fold op - Fold(Fold), + Fold(Spanned), /// Collection map op Map(Map), /// Collection filter op @@ -253,7 +253,7 @@ impl Expr { Expr::BinOp(v) => v.expr().tpe(), Expr::OptionGet(v) => v.expr().tpe(), Expr::ExtractRegisterAs(v) => v.expr().tpe(), - Expr::Fold(v) => v.tpe(), + Expr::Fold(v) => v.expr().tpe(), Expr::SelectField(v) => v.tpe(), Expr::ExtractAmount(v) => v.tpe(), Expr::And(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index d6de39343..1a171fb59 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -79,6 +79,7 @@ use crate::serialization::{ use crate::mir::xor_of::XorOf; use crate::serialization::types::TypeCode; +use crate::source_span::Spanned; impl Expr { /// Parse expression from byte stream. This function should be used instead of @@ -225,7 +226,7 @@ impl SigmaSerializable for Expr { None => c.sigma_serialize(w), }, Expr::Append(ap) => ap.expr().sigma_serialize_w_opcode(w), - Expr::Fold(op) => op.sigma_serialize_w_opcode(w), + Expr::Fold(op) => op.expr().sigma_serialize_w_opcode(w), Expr::ConstPlaceholder(cp) => cp.sigma_serialize_w_opcode(w), Expr::SubstConstants(s) => s.expr().sigma_serialize_w_opcode(w), Expr::ByteArrayToLong(s) => s.expr().sigma_serialize_w_opcode(w), @@ -304,6 +305,22 @@ impl SigmaSerializable for Expr { } } +impl SigmaSerializable for Spanned { + fn sigma_serialize(&self, w: &mut W) -> SigmaSerializeResult { + self.expr.sigma_serialize(w) + } + + fn sigma_parse(r: &mut R) -> Result { + T::sigma_parse(r).map(Into::into) + } +} + +impl HasOpCode for Spanned { + fn op_code(&self) -> OpCode { + self.expr.op_code() + } +} + #[cfg(test)] #[cfg(feature = "arbitrary")] #[allow(clippy::unwrap_used)] diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 2c8edf962..f6091e8d5 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -6,6 +6,7 @@ use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; +use crate::mir::coll_fold::Fold; use crate::mir::coll_slice::Slice; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; @@ -97,6 +98,7 @@ into_expr!(OptionIsDefined); into_expr!(OptionGetOrElse); into_expr!(ExtractRegisterAs); into_expr!(Slice); +into_expr!(Fold); impl From for Spanned { fn from(v: T) -> Self { @@ -155,7 +157,7 @@ impl Expr { Expr::ByIndex(op) => op.source_span, Expr::SizeOf(_) => SourceSpan::empty(), Expr::Slice(op) => op.source_span, - Expr::Fold(_) => todo!(), + Expr::Fold(op) => op.source_span, Expr::Map(_) => todo!(), Expr::Filter(_) => todo!(), Expr::Exists(_) => todo!(), From cbbc6d59e136a551c5aedcbd7c132431a0b784d8 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 14:33:10 +0300 Subject: [PATCH 46/74] wrap Filter, Fold and ForAll in Spanned; --- ergotree-ir/src/mir/expr.rs | 16 ++++++++-------- ergotree-ir/src/source_span.rs | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 174ef6c95..f208f4eaa 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -177,13 +177,13 @@ pub enum Expr { /// Collection fold op Fold(Spanned), /// Collection map op - Map(Map), + Map(Spanned), /// Collection filter op - Filter(Filter), + Filter(Spanned), /// Tests whether a predicate holds for at least one element of this collection - Exists(Exists), + Exists(Spanned), /// Tests whether a predicate holds for all elements of this collection. - ForAll(ForAll), + ForAll(Spanned), /// Tuple field access SelectField(SelectField), /// Bool to SigmaProp @@ -261,8 +261,8 @@ impl Expr { Expr::Xor(v) => v.tpe(), Expr::Atleast(v) => v.tpe(), Expr::LogicalNot(v) => v.tpe(), - Expr::Map(v) => v.tpe(), - Expr::Filter(v) => v.tpe(), + Expr::Map(v) => v.expr().tpe(), + Expr::Filter(v) => v.expr().tpe(), Expr::BoolToSigmaProp(v) => v.tpe(), Expr::Upcast(v) => v.tpe(), Expr::Downcast(v) => v.tpe(), @@ -274,14 +274,14 @@ impl Expr { Expr::CreateProveDlog(v) => v.tpe(), Expr::CreateProveDhTuple(v) => v.tpe(), Expr::ExtractCreationInfo(v) => v.tpe(), - Expr::Exists(v) => v.tpe(), + Expr::Exists(v) => v.expr().tpe(), Expr::ExtractId(v) => v.tpe(), Expr::SigmaPropBytes(v) => v.tpe(), Expr::OptionIsDefined(v) => v.expr().tpe(), Expr::OptionGetOrElse(v) => v.expr().tpe(), Expr::Negation(v) => v.expr().tpe(), Expr::BitInversion(v) => v.tpe(), - Expr::ForAll(v) => v.tpe(), + Expr::ForAll(v) => v.expr().tpe(), Expr::Tuple(v) => v.tpe(), Expr::DecodePoint(v) => v.tpe(), Expr::SigmaAnd(v) => v.tpe(), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index f6091e8d5..d0fcfdc9c 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -6,7 +6,11 @@ use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; +use crate::mir::coll_exists::Exists; +use crate::mir::coll_filter::Filter; use crate::mir::coll_fold::Fold; +use crate::mir::coll_forall::ForAll; +use crate::mir::coll_map::Map; use crate::mir::coll_slice::Slice; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; @@ -99,6 +103,10 @@ into_expr!(OptionGetOrElse); into_expr!(ExtractRegisterAs); into_expr!(Slice); into_expr!(Fold); +into_expr!(Map); +into_expr!(Filter); +into_expr!(Exists); +into_expr!(ForAll); impl From for Spanned { fn from(v: T) -> Self { @@ -158,10 +166,10 @@ impl Expr { Expr::SizeOf(_) => SourceSpan::empty(), Expr::Slice(op) => op.source_span, Expr::Fold(op) => op.source_span, - Expr::Map(_) => todo!(), - Expr::Filter(_) => todo!(), - Expr::Exists(_) => todo!(), - Expr::ForAll(_) => todo!(), + Expr::Map(op) => op.source_span, + Expr::Filter(op) => op.source_span, + Expr::Exists(op) => op.source_span, + Expr::ForAll(op) => op.source_span, Expr::SelectField(_) => todo!(), Expr::BoolToSigmaProp(_) => SourceSpan::empty(), Expr::Upcast(_) => SourceSpan::empty(), From 99489da15d14b0eed371e5febc24a68dde32442a Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 14:34:49 +0300 Subject: [PATCH 47/74] wrap SelectField in Spanned; --- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/serialization/expr.rs | 2 +- ergotree-ir/src/source_span.rs | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index f208f4eaa..d0f07f546 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -185,7 +185,7 @@ pub enum Expr { /// Tests whether a predicate holds for all elements of this collection. ForAll(Spanned), /// Tuple field access - SelectField(SelectField), + SelectField(Spanned), /// Bool to SigmaProp BoolToSigmaProp(BoolToSigmaProp), /// Upcast numeric value @@ -254,7 +254,7 @@ impl Expr { Expr::OptionGet(v) => v.expr().tpe(), Expr::ExtractRegisterAs(v) => v.expr().tpe(), Expr::Fold(v) => v.expr().tpe(), - Expr::SelectField(v) => v.tpe(), + Expr::SelectField(v) => v.expr().tpe(), Expr::ExtractAmount(v) => v.tpe(), Expr::And(v) => v.tpe(), Expr::Or(v) => v.tpe(), diff --git a/ergotree-ir/src/serialization/expr.rs b/ergotree-ir/src/serialization/expr.rs index 1a171fb59..4abb5eef8 100644 --- a/ergotree-ir/src/serialization/expr.rs +++ b/ergotree-ir/src/serialization/expr.rs @@ -155,7 +155,7 @@ impl Expr { OpCode::VAL_DEF => Ok(Expr::ValDef(ValDef::sigma_parse(r)?.into())), OpCode::VAL_USE => Ok(Expr::ValUse(ValUse::sigma_parse(r)?)), ExtractAmount::OP_CODE => Ok(Expr::ExtractAmount(ExtractAmount::sigma_parse(r)?)), - OpCode::SELECT_FIELD => Ok(Expr::SelectField(SelectField::sigma_parse(r)?)), + OpCode::SELECT_FIELD => Ok(Expr::SelectField(SelectField::sigma_parse(r)?.into())), OpCode::CALC_BLAKE2B256 => Ok(CalcBlake2b256::sigma_parse(r)?.into()), CalcSha256::OP_CODE => Ok(CalcSha256::sigma_parse(r)?.into()), And::OP_CODE => Ok(And::sigma_parse(r)?.into()), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index d0fcfdc9c..f138ca65d 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -20,6 +20,7 @@ use crate::mir::option_get::OptionGet; use crate::mir::option_get_or_else::OptionGetOrElse; use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; +use crate::mir::select_field::SelectField; use crate::mir::subst_const::SubstConstants; use crate::mir::val_def::ValDef; @@ -107,6 +108,7 @@ into_expr!(Map); into_expr!(Filter); into_expr!(Exists); into_expr!(ForAll); +into_expr!(SelectField); impl From for Spanned { fn from(v: T) -> Self { @@ -170,7 +172,7 @@ impl Expr { Expr::Filter(op) => op.source_span, Expr::Exists(op) => op.source_span, Expr::ForAll(op) => op.source_span, - Expr::SelectField(_) => todo!(), + Expr::SelectField(op) => op.source_span, Expr::BoolToSigmaProp(_) => SourceSpan::empty(), Expr::Upcast(_) => SourceSpan::empty(), Expr::Downcast(_) => SourceSpan::empty(), From 25c24f81d3c71a684068ed7c8437f0ba69114670 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 14:38:02 +0300 Subject: [PATCH 48/74] wrap SelectField and GetVar in Spanned; --- ergotree-interpreter/src/eval/coll_fold.rs | 4 ++-- ergotree-ir/src/chain/address.rs | 11 +++++++---- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/source_span.rs | 4 +++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ergotree-interpreter/src/eval/coll_fold.rs b/ergotree-interpreter/src/eval/coll_fold.rs index a32ff92c2..385870eaa 100644 --- a/ergotree-interpreter/src/eval/coll_fold.rs +++ b/ergotree-interpreter/src/eval/coll_fold.rs @@ -97,11 +97,11 @@ mod tests { let fold_op_body: Expr = BinOp { kind: ArithOp::Plus.into(), left: Box::new(Expr::SelectField( - SelectField::new(tuple.clone(), 1.try_into().unwrap()).unwrap(), + SelectField::new(tuple.clone(), 1.try_into().unwrap()).unwrap().into(), )), right: Box::new(Expr::ExtractAmount( ExtractAmount::try_build(Expr::SelectField( - SelectField::new(tuple, 2.try_into().unwrap()).unwrap(), + SelectField::new(tuple, 2.try_into().unwrap()).unwrap().into(), )) .unwrap(), )), diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index c07c1c153..43e2b9b5f 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -210,10 +210,13 @@ impl Address { } Address::P2S(bytes) => ErgoTree::sigma_parse_bytes(bytes), Address::P2SH(script_hash) => { - let get_var_expr = Expr::GetVar(GetVar { - var_id: 1, - var_tpe: SType::SColl(Box::new(SType::SByte)), - }); + let get_var_expr = Expr::GetVar( + GetVar { + var_id: 1, + var_tpe: SType::SColl(Box::new(SType::SByte)), + } + .into(), + ); let hash_expr = Expr::CalcBlake2b256(CalcBlake2b256 { input: Box::new(get_var_expr), }); diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index d0f07f546..a61ae927b 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -205,7 +205,7 @@ pub enum Expr { /// OR conjunction for sigma propositions SigmaOr(SigmaOr), /// Extracts Context variable by id and type - GetVar(GetVar), + GetVar(Spanned), /// Extract register of SELF box as `Coll[Byte]`, deserialize it into Value and inline into /// the executing script. DeserializeRegister(DeserializeRegister), @@ -288,7 +288,7 @@ impl Expr { Expr::SigmaOr(v) => v.tpe(), Expr::DeserializeRegister(v) => v.tpe(), Expr::DeserializeContext(v) => v.tpe(), - Expr::GetVar(v) => v.tpe(), + Expr::GetVar(v) => v.expr().tpe(), Expr::MultiplyGroup(v) => v.tpe(), Expr::Exponentiate(v) => v.tpe(), Expr::XorOf(v) => v.tpe(), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index f138ca65d..5814d38e4 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -14,6 +14,7 @@ use crate::mir::coll_map::Map; use crate::mir::coll_slice::Slice; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; +use crate::mir::get_var::GetVar; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; @@ -109,6 +110,7 @@ into_expr!(Filter); into_expr!(Exists); into_expr!(ForAll); into_expr!(SelectField); +into_expr!(GetVar); impl From for Spanned { fn from(v: T) -> Self { @@ -182,7 +184,7 @@ impl Expr { Expr::DecodePoint(_) => SourceSpan::empty(), Expr::SigmaAnd(_) => SourceSpan::empty(), Expr::SigmaOr(_) => SourceSpan::empty(), - Expr::GetVar(_) => todo!(), + Expr::GetVar(op) => op.source_span, Expr::DeserializeRegister(_) => todo!(), Expr::DeserializeContext(_) => todo!(), Expr::MultiplyGroup(_) => SourceSpan::empty(), From dd6ac14675e59cbe872106cbfa7d80123ce8b2b5 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 14:42:02 +0300 Subject: [PATCH 49/74] wrap Deserialize* into Spanned; --- ergotree-ir/src/chain/address.rs | 17 +++++++++++------ ergotree-ir/src/mir/expr.rs | 8 ++++---- ergotree-ir/src/source_span.rs | 8 ++++++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index 43e2b9b5f..5a11b1fee 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -108,8 +108,10 @@ impl Address { Err(_) => Address::P2S(tree.sigma_serialize_bytes()?), }, Expr::SigmaAnd(SigmaAnd { items }) => { - if let [Expr::BoolToSigmaProp(BoolToSigmaProp { input }), Expr::DeserializeContext(DeserializeContext { tpe, id })] = - items.as_slice() + if let [Expr::BoolToSigmaProp(BoolToSigmaProp { input }), Expr::DeserializeContext(Spanned { + expr: DeserializeContext { tpe, id }, + .. + })] = items.as_slice() { if let ( Expr::BinOp(Spanned { @@ -236,10 +238,13 @@ impl Address { } .into(), ); - let script_is_correct = Expr::DeserializeContext(DeserializeContext { - tpe: SType::SSigmaProp, - id: 1, - }); + let script_is_correct = Expr::DeserializeContext( + DeserializeContext { + tpe: SType::SSigmaProp, + id: 1, + } + .into(), + ); let sigma_prop = Expr::BoolToSigmaProp(BoolToSigmaProp { input: Box::from(hash_equals), }); diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index a61ae927b..22b7d2061 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -208,12 +208,12 @@ pub enum Expr { GetVar(Spanned), /// Extract register of SELF box as `Coll[Byte]`, deserialize it into Value and inline into /// the executing script. - DeserializeRegister(DeserializeRegister), + DeserializeRegister(Spanned), /// Extracts context variable as `Coll[Byte]`, deserializes it to script and then executes /// this script in the current context. The original `Coll[Byte]` of the script is /// available as `getVar[Coll[Byte]](id)` On evaluation returns the result of the /// script execution in the current context - DeserializeContext(DeserializeContext), + DeserializeContext(Spanned), /// MultiplyGroup op for GroupElement MultiplyGroup(MultiplyGroup), /// Exponentiate op for GroupElement @@ -286,8 +286,8 @@ impl Expr { Expr::DecodePoint(v) => v.tpe(), Expr::SigmaAnd(v) => v.tpe(), Expr::SigmaOr(v) => v.tpe(), - Expr::DeserializeRegister(v) => v.tpe(), - Expr::DeserializeContext(v) => v.tpe(), + Expr::DeserializeRegister(v) => v.expr().tpe(), + Expr::DeserializeContext(v) => v.expr().tpe(), Expr::GetVar(v) => v.expr().tpe(), Expr::MultiplyGroup(v) => v.tpe(), Expr::Exponentiate(v) => v.tpe(), diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 5814d38e4..5dacbf9c8 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -12,6 +12,8 @@ use crate::mir::coll_fold::Fold; use crate::mir::coll_forall::ForAll; use crate::mir::coll_map::Map; use crate::mir::coll_slice::Slice; +use crate::mir::deserialize_context::DeserializeContext; +use crate::mir::deserialize_register::DeserializeRegister; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; use crate::mir::get_var::GetVar; @@ -111,6 +113,8 @@ into_expr!(Exists); into_expr!(ForAll); into_expr!(SelectField); into_expr!(GetVar); +into_expr!(DeserializeRegister); +into_expr!(DeserializeContext); impl From for Spanned { fn from(v: T) -> Self { @@ -185,8 +189,8 @@ impl Expr { Expr::SigmaAnd(_) => SourceSpan::empty(), Expr::SigmaOr(_) => SourceSpan::empty(), Expr::GetVar(op) => op.source_span, - Expr::DeserializeRegister(_) => todo!(), - Expr::DeserializeContext(_) => todo!(), + Expr::DeserializeRegister(op) => op.source_span, + Expr::DeserializeContext(op) => op.source_span, Expr::MultiplyGroup(_) => SourceSpan::empty(), Expr::Exponentiate(_) => SourceSpan::empty(), Expr::XorOf(_) => SourceSpan::empty(), From 986fc41822eb2f898577dc7413ec21ad0222a10d Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 14:43:16 +0300 Subject: [PATCH 50/74] wrap TreeLookup in Spanned; --- ergotree-ir/src/mir/expr.rs | 4 ++-- ergotree-ir/src/source_span.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 22b7d2061..226aae903 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -221,7 +221,7 @@ pub enum Expr { /// XOR for collection of booleans XorOf(XorOf), /// Perform a lookup by key in an AVL tree - TreeLookup(TreeLookup), + TreeLookup(Spanned), /// Create an AVL tree CreateAvlTree(CreateAvlTree), } @@ -294,7 +294,7 @@ impl Expr { Expr::XorOf(v) => v.tpe(), Expr::ExtractBytes(v) => v.tpe(), Expr::ExtractBytesWithNoRef(v) => v.tpe(), - Expr::TreeLookup(v) => v.tpe(), + Expr::TreeLookup(v) => v.expr().tpe(), Expr::CreateAvlTree(v) => v.tpe(), } } diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 5dacbf9c8..acd098291 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -25,6 +25,7 @@ use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; use crate::mir::select_field::SelectField; use crate::mir::subst_const::SubstConstants; +use crate::mir::tree_lookup::TreeLookup; use crate::mir::val_def::ValDef; /// Source position for the Expr @@ -115,6 +116,7 @@ into_expr!(SelectField); into_expr!(GetVar); into_expr!(DeserializeRegister); into_expr!(DeserializeContext); +into_expr!(TreeLookup); impl From for Spanned { fn from(v: T) -> Self { @@ -127,7 +129,6 @@ impl From for Spanned { impl Expr { /// Source span for the Expr - #[allow(clippy::todo)] pub fn span(&self) -> SourceSpan { match self { Expr::Append(op) => op.source_span, @@ -194,7 +195,7 @@ impl Expr { Expr::MultiplyGroup(_) => SourceSpan::empty(), Expr::Exponentiate(_) => SourceSpan::empty(), Expr::XorOf(_) => SourceSpan::empty(), - Expr::TreeLookup(_) => todo!(), + Expr::TreeLookup(op) => op.source_span, Expr::CreateAvlTree(_) => SourceSpan::empty(), } } From 1e282b6cec47fcc2c795a190893a15433c172cd1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 15:35:28 +0300 Subject: [PATCH 51/74] fix expected formatting in pretty printer tests; --- ergotree-ir/src/pretty_printer.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 9fb6caeac..4e9bc01d8 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -364,8 +364,8 @@ mod tests { expr, expect![[r#" { - val v1 = 1 - v1 + val v1 = 1 + v1 } "#]], ); @@ -402,8 +402,8 @@ mod tests { expr.clone(), expect![[r#" { - val v1 = 4 / 2 - v1 + val v1 = 4 / 2 + v1 } "#]], ); From 9eb85a16d9c175489dac81f8de18b538dd66ac38 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 22 Aug 2023 15:36:30 +0300 Subject: [PATCH 52/74] fix formatting; --- ergotree-interpreter/src/eval/subst_const.rs | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/ergotree-interpreter/src/eval/subst_const.rs b/ergotree-interpreter/src/eval/subst_const.rs index ed27ceee1..c92943f1f 100644 --- a/ergotree-interpreter/src/eval/subst_const.rs +++ b/ergotree-interpreter/src/eval/subst_const.rs @@ -131,11 +131,14 @@ mod tests { let positions = Expr::Const(Constant::from(vec![0])).into(); let new_values = Expr::Const(Constant::from(vec![new.clone()])).into(); - let subst_const = Expr::SubstConstants(SubstConstants { - script_bytes, - positions, - new_values, - }.into()); + let subst_const = Expr::SubstConstants( + SubstConstants { + script_bytes, + positions, + new_values, + } + .into(), + ); let x: Value = try_eval_out_wo_ctx(&subst_const).unwrap(); if let Value::Coll(CollKind::NativeColl(NativeColl::CollByte(b))) = x { @@ -178,11 +181,14 @@ mod tests { let new_values = Expr::Const(Constant::from(vec![n0, n1, n2])).into(); - let subst_const = Expr::SubstConstants(SubstConstants { - script_bytes, - positions, - new_values, - }.into()); + let subst_const = Expr::SubstConstants( + SubstConstants { + script_bytes, + positions, + new_values, + } + .into(), + ); let x: Value = try_eval_out_wo_ctx(&subst_const).unwrap(); if let Value::Coll(CollKind::NativeColl(NativeColl::CollByte(b))) = x { From 6bb67612adbcc762c62d8762d20fa1d334964fe8 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 23 Aug 2023 15:53:29 +0300 Subject: [PATCH 53/74] update expected source spans in binop pretty print test; --- ergotree-ir/src/pretty_printer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 4e9bc01d8..f5d31a1fd 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -411,7 +411,7 @@ mod tests { check_spans( expr, expect![[ - r#"BlockValue(Spanned { source_span: SourceSpan { offset: 0, length: 30 }, expr: BlockValue { items: [ValDef(Spanned { source_span: SourceSpan { offset: 6, length: 14 }, expr: ValDef { id: ValId(1), rhs: BinOp(Spanned { source_span: SourceSpan { offset: 15, length: 5 }, expr: BinOp { kind: Arith(Divide), left: Const("4: SInt"), right: Const("2: SInt") } }) } })], result: ValUse(ValUse { val_id: ValId(1), tpe: SInt }) } })"# + r#"BlockValue(Spanned { source_span: SourceSpan { offset: 0, length: 26 }, expr: BlockValue { items: [ValDef(Spanned { source_span: SourceSpan { offset: 6, length: 14 }, expr: ValDef { id: ValId(1), rhs: BinOp(Spanned { source_span: SourceSpan { offset: 13, length: 5 }, expr: BinOp { kind: Arith(Divide), left: Const("4: SInt"), right: Const("2: SInt") } }) } })], result: ValUse(ValUse { val_id: ValId(1), tpe: SInt }) } })"# ]], ); } From 91e2a0f7f0b572c016e2251f6f0e889186a376a1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 23 Aug 2023 16:43:46 +0300 Subject: [PATCH 54/74] skip ConstPlaceholder in pretty printer; --- ergotree-ir/src/pretty_printer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index f5d31a1fd..5264a5849 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -166,7 +166,7 @@ impl Print for Expr { Expr::BinOp(v) => v.expr().print(w), Expr::GlobalVars(v) => v.print(w), Expr::ByIndex(v) => v.expr().print(w), - Expr::ConstPlaceholder(_) => todo!(), + Expr::ConstPlaceholder(_) => Ok(self.clone()), Expr::SubstConstants(_) => todo!(), Expr::ByteArrayToLong(_) => todo!(), Expr::ByteArrayToBigInt(_) => todo!(), From 5b3873b77c45364743258a9113d77b3f870c3819 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 23 Aug 2023 16:45:13 +0300 Subject: [PATCH 55/74] fix source span in expected pretty printer test; --- ergotree-ir/src/pretty_printer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 5264a5849..6a9c9c269 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -411,7 +411,7 @@ mod tests { check_spans( expr, expect![[ - r#"BlockValue(Spanned { source_span: SourceSpan { offset: 0, length: 26 }, expr: BlockValue { items: [ValDef(Spanned { source_span: SourceSpan { offset: 6, length: 14 }, expr: ValDef { id: ValId(1), rhs: BinOp(Spanned { source_span: SourceSpan { offset: 13, length: 5 }, expr: BinOp { kind: Arith(Divide), left: Const("4: SInt"), right: Const("2: SInt") } }) } })], result: ValUse(ValUse { val_id: ValId(1), tpe: SInt }) } })"# + r#"BlockValue(Spanned { source_span: SourceSpan { offset: 0, length: 26 }, expr: BlockValue { items: [ValDef(Spanned { source_span: SourceSpan { offset: 4, length: 14 }, expr: ValDef { id: ValId(1), rhs: BinOp(Spanned { source_span: SourceSpan { offset: 13, length: 5 }, expr: BinOp { kind: Arith(Divide), left: Const("4: SInt"), right: Const("2: SInt") } }) } })], result: ValUse(ValUse { val_id: ValId(1), tpe: SInt }) } })"# ]], ); } From 824ed246459c407b70154efdb86f544ff6c6f692 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 4 Sep 2023 15:39:48 +0300 Subject: [PATCH 56/74] move Print trait and implementations into a separate module; --- ergotree-ir/src/pretty_printer.rs | 228 +----------------------- ergotree-ir/src/pretty_printer/print.rs | 227 +++++++++++++++++++++++ 2 files changed, 230 insertions(+), 225 deletions(-) create mode 100644 ergotree-ir/src/pretty_printer/print.rs diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 6a9c9c269..48eab08ac 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -2,231 +2,8 @@ use std::fmt::Write; -use thiserror::Error; - -use crate::mir::bin_op::BinOp; -use crate::mir::block::BlockValue; -use crate::mir::coll_append::Append; -use crate::mir::coll_by_index::ByIndex; -use crate::mir::constant::Constant; -use crate::mir::expr::Expr; -use crate::mir::global_vars::GlobalVars; -use crate::mir::val_def::ValDef; -use crate::mir::val_use::ValUse; -use crate::source_span::SourceSpan; -use crate::source_span::Spanned; - -/// Print error -#[allow(missing_docs)] -#[derive(PartialEq, Eq, Debug, Clone, Error)] -pub enum PrintError { - #[error("fmt error: {0:?}")] - FmtError(#[from] std::fmt::Error), -} - -/// Print trait for Expr that sets the source span for the resulting Expr -pub trait Print { - /// Print the expression and return the resulting expression with source span - fn print(&self, w: &mut dyn Printer) -> Result; -} - -impl Print for BlockValue { - fn print(&self, w: &mut dyn Printer) -> Result { - let offset = w.current_pos(); - writeln!(w, "{{")?; - w.inc_ident(); - let indent = w.get_indent(); - let mut items = Vec::new(); - for item in &self.items { - write!(w, "{:indent$}", "", indent = indent)?; - items.push(item.print(w)?); - writeln!(w)?; - } - // indent for result - write!(w, "{:indent$}", "", indent = indent)?; - let res = self.result.print(w)?; - w.dec_ident(); - writeln!(w, "\n}}")?; - let length = w.current_pos() - offset; - Ok(Spanned { - source_span: SourceSpan { offset, length }, - expr: BlockValue { - items, - result: Box::new(res), - }, - } - .into()) - } -} - -impl Print for ValDef { - fn print(&self, w: &mut dyn Printer) -> Result { - let offset = w.current_pos(); - write!(w, "val v{} = ", self.id)?; - let rhs = self.rhs.print(w)?; - let length = w.current_pos() - offset; - Ok(Spanned { - source_span: SourceSpan { offset, length }, - expr: ValDef { - id: self.id, - rhs: Box::new(rhs), - }, - } - .into()) - } -} - -impl Print for Constant { - fn print(&self, w: &mut dyn Printer) -> Result { - write!(w, "{:?}", self.v)?; - Ok(self.clone().into()) - } -} - -impl Print for ValUse { - fn print(&self, w: &mut dyn Printer) -> Result { - write!(w, "v{}", self.val_id)?; - Ok(self.clone().into()) - } -} - -impl Print for Append { - fn print(&self, w: &mut dyn Printer) -> Result { - let offset = w.current_pos(); - let input = self.input.print(w)?; - write!(w, ".append(")?; - let col_2 = self.col_2.print(w)?; - write!(w, ")")?; - let length = w.current_pos() - offset; - Ok(Spanned { - source_span: SourceSpan { offset, length }, - expr: Append { - input: Box::new(input), - col_2: Box::new(col_2), - }, - } - .into()) - } -} - -impl Print for BinOp { - fn print(&self, w: &mut dyn Printer) -> Result { - let offset = w.current_pos(); - let left = self.left.print(w)?; - write!(w, " {} ", self.kind)?; - let right = self.right.print(w)?; - let length = w.current_pos() - offset; - // dbg!(offset, length); - Ok(Spanned { - source_span: SourceSpan { offset, length }, - expr: BinOp { - kind: self.kind, - left: Box::new(left), - right: Box::new(right), - }, - } - .into()) - } -} - -impl Print for GlobalVars { - fn print(&self, w: &mut dyn Printer) -> Result { - write!(w, "{}", self)?; - Ok(self.clone().into()) - } -} - -impl Print for ByIndex { - fn print(&self, w: &mut dyn Printer) -> Result { - let input = self.input.print(w)?; - let offset = w.current_pos(); - write!(w, "(")?; - let index = self.index.print(w)?; - write!(w, ")")?; - let length = w.current_pos() - offset; - #[allow(clippy::unwrap_used)] // we only added spans - Ok(Spanned { - source_span: SourceSpan { offset, length }, - expr: ByIndex::new(input, index, self.default.clone()).unwrap(), - } - .into()) - } -} - -#[allow(clippy::todo)] -#[allow(clippy::panic)] -impl Print for Expr { - fn print(&self, w: &mut dyn Printer) -> Result { - match self { - Expr::Append(v) => v.expr().print(w), - Expr::BlockValue(v) => v.expr().print(w), - Expr::ValDef(v) => v.expr().print(w), - Expr::ValUse(v) => v.print(w), - Expr::Const(v) => v.print(w), - Expr::BinOp(v) => v.expr().print(w), - Expr::GlobalVars(v) => v.print(w), - Expr::ByIndex(v) => v.expr().print(w), - Expr::ConstPlaceholder(_) => Ok(self.clone()), - Expr::SubstConstants(_) => todo!(), - Expr::ByteArrayToLong(_) => todo!(), - Expr::ByteArrayToBigInt(_) => todo!(), - Expr::LongToByteArray(_) => todo!(), - Expr::Collection(_) => todo!(), - Expr::Tuple(_) => todo!(), - Expr::CalcBlake2b256(_) => todo!(), - Expr::CalcSha256(_) => todo!(), - Expr::Context => todo!(), - Expr::Global => todo!(), - Expr::FuncValue(_) => todo!(), - Expr::Apply(_) => todo!(), - Expr::MethodCall(_) => todo!(), - Expr::PropertyCall(_) => todo!(), - Expr::If(_) => todo!(), - Expr::And(_) => todo!(), - Expr::Or(_) => todo!(), - Expr::Xor(_) => todo!(), - Expr::Atleast(_) => todo!(), - Expr::LogicalNot(_) => todo!(), - Expr::Negation(_) => todo!(), - Expr::BitInversion(_) => todo!(), - Expr::OptionGet(_) => todo!(), - Expr::OptionIsDefined(_) => todo!(), - Expr::OptionGetOrElse(_) => todo!(), - Expr::ExtractAmount(_) => todo!(), - Expr::ExtractRegisterAs(_) => todo!(), - Expr::ExtractBytes(_) => todo!(), - Expr::ExtractBytesWithNoRef(_) => todo!(), - Expr::ExtractScriptBytes(_) => todo!(), - Expr::ExtractCreationInfo(_) => todo!(), - Expr::ExtractId(_) => todo!(), - Expr::SizeOf(_) => todo!(), - Expr::Slice(_) => todo!(), - Expr::Fold(_) => todo!(), - Expr::Map(_) => todo!(), - Expr::Filter(_) => todo!(), - Expr::Exists(_) => todo!(), - Expr::ForAll(_) => todo!(), - Expr::SelectField(_) => todo!(), - Expr::BoolToSigmaProp(_) => todo!(), - Expr::Upcast(_) => todo!(), - Expr::Downcast(_) => todo!(), - Expr::CreateProveDlog(_) => todo!(), - Expr::CreateProveDhTuple(_) => todo!(), - Expr::SigmaPropBytes(_) => todo!(), - Expr::DecodePoint(_) => todo!(), - Expr::SigmaAnd(_) => todo!(), - Expr::SigmaOr(_) => todo!(), - Expr::GetVar(_) => todo!(), - Expr::DeserializeRegister(_) => todo!(), - Expr::DeserializeContext(_) => todo!(), - Expr::MultiplyGroup(_) => todo!(), - Expr::Exponentiate(_) => todo!(), - Expr::XorOf(_) => todo!(), - Expr::TreeLookup(_) => todo!(), - Expr::CreateAvlTree(_) => todo!(), - } - } -} +mod print; +pub use print::Print; // TODO: extract to a separate module /// Printer trait with tracking of current position and indent @@ -312,6 +89,7 @@ mod tests { use crate::mir::bin_op::ArithOp; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; + use crate::mir::expr::Expr; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; use crate::types::stype::SType; diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs new file mode 100644 index 000000000..3fcc3679c --- /dev/null +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -0,0 +1,227 @@ +use thiserror::Error; + +use crate::mir::bin_op::BinOp; +use crate::mir::block::BlockValue; +use crate::mir::coll_append::Append; +use crate::mir::coll_by_index::ByIndex; +use crate::mir::constant::Constant; +use crate::mir::expr::Expr; +use crate::mir::global_vars::GlobalVars; +use crate::mir::val_def::ValDef; +use crate::mir::val_use::ValUse; +use crate::source_span::SourceSpan; +use crate::source_span::Spanned; + +use super::Printer; + +/// Print error +#[allow(missing_docs)] +#[derive(PartialEq, Eq, Debug, Clone, Error)] +pub enum PrintError { + #[error("fmt error: {0:?}")] + FmtError(#[from] std::fmt::Error), +} + +/// Print trait for Expr that sets the source span for the resulting Expr +pub trait Print { + /// Print the expression and return the resulting expression with source span + fn print(&self, w: &mut dyn Printer) -> Result; +} + +impl Print for BlockValue { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + writeln!(w, "{{")?; + w.inc_ident(); + let indent = w.get_indent(); + let mut items = Vec::new(); + for item in &self.items { + write!(w, "{:indent$}", "", indent = indent)?; + items.push(item.print(w)?); + writeln!(w)?; + } + // indent for result + write!(w, "{:indent$}", "", indent = indent)?; + let res = self.result.print(w)?; + w.dec_ident(); + writeln!(w, "\n}}")?; + let length = w.current_pos() - offset; + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: BlockValue { + items, + result: Box::new(res), + }, + } + .into()) + } +} + +impl Print for ValDef { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + write!(w, "val v{} = ", self.id)?; + let rhs = self.rhs.print(w)?; + let length = w.current_pos() - offset; + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: ValDef { + id: self.id, + rhs: Box::new(rhs), + }, + } + .into()) + } +} + +impl Print for Constant { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "{:?}", self.v)?; + Ok(self.clone().into()) + } +} + +impl Print for ValUse { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "v{}", self.val_id)?; + Ok(self.clone().into()) + } +} + +impl Print for Append { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".append(")?; + let col_2 = self.col_2.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: Append { + input: Box::new(input), + col_2: Box::new(col_2), + }, + } + .into()) + } +} + +impl Print for BinOp { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let left = self.left.print(w)?; + write!(w, " {} ", self.kind)?; + let right = self.right.print(w)?; + let length = w.current_pos() - offset; + // dbg!(offset, length); + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: BinOp { + kind: self.kind, + left: Box::new(left), + right: Box::new(right), + }, + } + .into()) + } +} + +impl Print for GlobalVars { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "{}", self)?; + Ok(self.clone().into()) + } +} + +impl Print for ByIndex { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + let offset = w.current_pos(); + write!(w, "(")?; + let index = self.index.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: ByIndex::new(input, index, self.default.clone()).unwrap(), + } + .into()) + } +} + +#[allow(clippy::todo)] +#[allow(clippy::panic)] +impl Print for Expr { + fn print(&self, w: &mut dyn Printer) -> Result { + match self { + Expr::Append(v) => v.expr().print(w), + Expr::BlockValue(v) => v.expr().print(w), + Expr::ValDef(v) => v.expr().print(w), + Expr::ValUse(v) => v.print(w), + Expr::Const(v) => v.print(w), + Expr::BinOp(v) => v.expr().print(w), + Expr::GlobalVars(v) => v.print(w), + Expr::ByIndex(v) => v.expr().print(w), + Expr::ConstPlaceholder(_) => Ok(self.clone()), + Expr::SubstConstants(_) => todo!(), + Expr::ByteArrayToLong(_) => todo!(), + Expr::ByteArrayToBigInt(_) => todo!(), + Expr::LongToByteArray(_) => todo!(), + Expr::Collection(_) => todo!(), + Expr::Tuple(_) => todo!(), + Expr::CalcBlake2b256(_) => todo!(), + Expr::CalcSha256(_) => todo!(), + Expr::Context => todo!(), + Expr::Global => todo!(), + Expr::FuncValue(_) => todo!(), + Expr::Apply(_) => todo!(), + Expr::MethodCall(_) => todo!(), + Expr::PropertyCall(_) => todo!(), + Expr::If(_) => todo!(), + Expr::And(_) => todo!(), + Expr::Or(_) => todo!(), + Expr::Xor(_) => todo!(), + Expr::Atleast(_) => todo!(), + Expr::LogicalNot(_) => todo!(), + Expr::Negation(_) => todo!(), + Expr::BitInversion(_) => todo!(), + Expr::OptionGet(_) => todo!(), + Expr::OptionIsDefined(_) => todo!(), + Expr::OptionGetOrElse(_) => todo!(), + Expr::ExtractAmount(_) => todo!(), + Expr::ExtractRegisterAs(_) => todo!(), + Expr::ExtractBytes(_) => todo!(), + Expr::ExtractBytesWithNoRef(_) => todo!(), + Expr::ExtractScriptBytes(_) => todo!(), + Expr::ExtractCreationInfo(_) => todo!(), + Expr::ExtractId(_) => todo!(), + Expr::SizeOf(_) => todo!(), + Expr::Slice(_) => todo!(), + Expr::Fold(_) => todo!(), + Expr::Map(_) => todo!(), + Expr::Filter(_) => todo!(), + Expr::Exists(_) => todo!(), + Expr::ForAll(_) => todo!(), + Expr::SelectField(_) => todo!(), + Expr::BoolToSigmaProp(_) => todo!(), + Expr::Upcast(_) => todo!(), + Expr::Downcast(_) => todo!(), + Expr::CreateProveDlog(_) => todo!(), + Expr::CreateProveDhTuple(_) => todo!(), + Expr::SigmaPropBytes(_) => todo!(), + Expr::DecodePoint(_) => todo!(), + Expr::SigmaAnd(_) => todo!(), + Expr::SigmaOr(_) => todo!(), + Expr::GetVar(_) => todo!(), + Expr::DeserializeRegister(_) => todo!(), + Expr::DeserializeContext(_) => todo!(), + Expr::MultiplyGroup(_) => todo!(), + Expr::Exponentiate(_) => todo!(), + Expr::XorOf(_) => todo!(), + Expr::TreeLookup(_) => todo!(), + Expr::CreateAvlTree(_) => todo!(), + } + } +} From 40301df5bd0bb48353360cf0db2e175c120737e1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 5 Sep 2023 12:59:43 +0300 Subject: [PATCH 57/74] add EIP23 refresh contract as pretty printer test; Implement Print for various IR nodes; --- ergotree-ir/src/mir/func_value.rs | 8 + ergotree-ir/src/mir/select_field.rs | 2 +- ergotree-ir/src/pretty_printer.rs | 13 + ergotree-ir/src/pretty_printer/print.rs | 366 +++++++++++++++++++----- 4 files changed, 318 insertions(+), 71 deletions(-) diff --git a/ergotree-ir/src/mir/func_value.rs b/ergotree-ir/src/mir/func_value.rs index e313a35e0..83ab57552 100644 --- a/ergotree-ir/src/mir/func_value.rs +++ b/ergotree-ir/src/mir/func_value.rs @@ -1,3 +1,5 @@ +use std::fmt; + use crate::has_opcode::HasStaticOpCode; use crate::serialization::op_code::OpCode; use crate::serialization::sigma_byte_reader::SigmaByteRead; @@ -37,6 +39,12 @@ impl SigmaSerializable for FuncArg { } } +impl std::fmt::Display for FuncArg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "v{}: {}", self.idx, self.tpe) + } +} + /// User-defined function #[derive(PartialEq, Eq, Debug, Clone)] pub struct FuncValue { diff --git a/ergotree-ir/src/mir/select_field.rs b/ergotree-ir/src/mir/select_field.rs index c84dc42b1..02f5bd306 100644 --- a/ergotree-ir/src/mir/select_field.rs +++ b/ergotree-ir/src/mir/select_field.rs @@ -14,7 +14,7 @@ use super::expr::InvalidArgumentError; use crate::has_opcode::HasStaticOpCode; /// Tuple field access index (1..=255) -#[derive(PartialEq, Eq, Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone, derive_more::Display)] pub struct TupleFieldIndex(u8); /// Error for tuple index being out of bounds (1..=255) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 48eab08ac..dda02ba18 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -86,12 +86,14 @@ mod tests { use expect_test::expect; + use crate::ergo_tree::ErgoTree; use crate::mir::bin_op::ArithOp; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::expr::Expr; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; + use crate::serialization::SigmaSerializable; use crate::types::stype::SType; use super::*; @@ -193,4 +195,15 @@ mod tests { ]], ); } + + #[test] + fn eip23_refresh_contract() { + let ergo_tree_bytes = base16::decode("1016043c040004000e202a472d4a614e645267556b58703273357638792f423f4528482b4d625065536801000502010105000400040004020402040204080400040a05c8010e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570400040404020408d80ed60199a37300d602b2a4730100d603b5a4d901036395e6c672030605eded928cc77203017201938cb2db6308720373020001730393e4c672030504e4c6720205047304d604b17203d605b0720386027305860273067307d901053c413d0563d803d607e4c68c7205020605d6088c720501d6098c720802860272078602ed8c720901908c72080172079a8c7209027207d6068c720502d6078c720501d608db63087202d609b27208730800d60ab2a5730900d60bdb6308720ad60cb2720b730a00d60db27208730b00d60eb2a5730c00ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02cde4c6b27203e4e30004000407d18f8cc77202017201d1927204730dd18c720601d190997207e4c6b27203730e0006059d9c72077e730f057310d1938c7209017311d193b2720b7312007209d1938c720c018c720d01d1928c720c02998c720d027e9c7204731305d193b1720bb17208d193e4c6720a04059d8c7206027e720405d193e4c6720a05049ae4c6720205047314d193c2720ac27202d192c1720ac17202d1928cc7720a0199a37315d193db6308720edb6308a7d193c2720ec2a7d192c1720ec1a7").unwrap(); + let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap(); + check_pretty( + ergo_tree.proposition().unwrap(), + expect![[r#" + "#]], + ) + } } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 3fcc3679c..4a69d8476 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -4,13 +4,28 @@ use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; +use crate::mir::coll_filter::Filter; +use crate::mir::coll_fold::Fold; +use crate::mir::coll_map::Map; +use crate::mir::coll_size::SizeOf; use crate::mir::constant::Constant; use crate::mir::expr::Expr; +use crate::mir::extract_creation_info::ExtractCreationInfo; +use crate::mir::extract_reg_as::ExtractRegisterAs; +use crate::mir::func_value::FuncValue; use crate::mir::global_vars::GlobalVars; +use crate::mir::if_op::If; +use crate::mir::option_get::OptionGet; +use crate::mir::option_is_defined::OptionIsDefined; +use crate::mir::property_call::PropertyCall; +use crate::mir::select_field::SelectField; +use crate::mir::tuple::Tuple; +use crate::mir::unary_op::OneArgOpTryBuild; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; use crate::source_span::SourceSpan; use crate::source_span::Spanned; +use crate::types::stype::SType; use super::Printer; @@ -28,6 +43,80 @@ pub trait Print { fn print(&self, w: &mut dyn Printer) -> Result; } +#[allow(clippy::todo)] +impl Print for Expr { + fn print(&self, w: &mut dyn Printer) -> Result { + match self { + Expr::Append(v) => v.expr().print(w), + Expr::BlockValue(v) => v.expr().print(w), + Expr::ValDef(v) => v.expr().print(w), + Expr::ValUse(v) => v.print(w), + Expr::Const(v) => v.print(w), + Expr::BinOp(v) => v.expr().print(w), + Expr::GlobalVars(v) => v.print(w), + Expr::ByIndex(v) => v.expr().print(w), + Expr::ConstPlaceholder(_) => Ok(self.clone()), + Expr::SubstConstants(_) => todo!(), + Expr::ByteArrayToLong(_) => todo!(), + Expr::ByteArrayToBigInt(_) => todo!(), + Expr::LongToByteArray(_) => todo!(), + Expr::Collection(_) => todo!(), + Expr::Tuple(v) => v.print(w), + Expr::CalcBlake2b256(_) => todo!(), + Expr::CalcSha256(_) => todo!(), + Expr::Context => todo!(), + Expr::Global => todo!(), + Expr::FuncValue(v) => v.print(w), + Expr::Apply(_) => todo!(), + Expr::MethodCall(_) => todo!(), + Expr::PropertyCall(v) => v.expr().print(w), + Expr::If(v) => v.print(w), + Expr::And(_) => todo!(), + Expr::Or(_) => todo!(), + Expr::Xor(_) => todo!(), + Expr::Atleast(_) => todo!(), + Expr::LogicalNot(_) => todo!(), + Expr::Negation(_) => todo!(), + Expr::BitInversion(_) => todo!(), + Expr::OptionGet(v) => v.expr().print(w), + Expr::OptionIsDefined(v) => v.expr().print(w), + Expr::OptionGetOrElse(_) => todo!(), + Expr::ExtractAmount(_) => todo!(), + Expr::ExtractRegisterAs(v) => v.expr().print(w), + Expr::ExtractBytes(_) => todo!(), + Expr::ExtractBytesWithNoRef(_) => todo!(), + Expr::ExtractScriptBytes(_) => todo!(), + Expr::ExtractCreationInfo(v) => v.print(w), + Expr::ExtractId(_) => todo!(), + Expr::SizeOf(v) => v.print(w), + Expr::Slice(_) => todo!(), + Expr::Fold(v) => v.expr().print(w), + Expr::Map(v) => v.expr().print(w), + Expr::Filter(v) => v.expr().print(w), + Expr::Exists(_) => todo!(), + Expr::ForAll(_) => todo!(), + Expr::SelectField(v) => v.expr().print(w), + Expr::BoolToSigmaProp(_) => todo!(), + Expr::Upcast(_) => todo!(), + Expr::Downcast(_) => todo!(), + Expr::CreateProveDlog(_) => todo!(), + Expr::CreateProveDhTuple(_) => todo!(), + Expr::SigmaPropBytes(_) => todo!(), + Expr::DecodePoint(_) => todo!(), + Expr::SigmaAnd(_) => todo!(), + Expr::SigmaOr(_) => todo!(), + Expr::GetVar(_) => todo!(), + Expr::DeserializeRegister(_) => todo!(), + Expr::DeserializeContext(_) => todo!(), + Expr::MultiplyGroup(_) => todo!(), + Expr::Exponentiate(_) => todo!(), + Expr::XorOf(_) => todo!(), + Expr::TreeLookup(_) => todo!(), + Expr::CreateAvlTree(_) => todo!(), + } + } +} + impl Print for BlockValue { fn print(&self, w: &mut dyn Printer) -> Result { let offset = w.current_pos(); @@ -151,77 +240,214 @@ impl Print for ByIndex { } } -#[allow(clippy::todo)] -#[allow(clippy::panic)] -impl Print for Expr { +impl Print for Map { fn print(&self, w: &mut dyn Printer) -> Result { - match self { - Expr::Append(v) => v.expr().print(w), - Expr::BlockValue(v) => v.expr().print(w), - Expr::ValDef(v) => v.expr().print(w), - Expr::ValUse(v) => v.print(w), - Expr::Const(v) => v.print(w), - Expr::BinOp(v) => v.expr().print(w), - Expr::GlobalVars(v) => v.print(w), - Expr::ByIndex(v) => v.expr().print(w), - Expr::ConstPlaceholder(_) => Ok(self.clone()), - Expr::SubstConstants(_) => todo!(), - Expr::ByteArrayToLong(_) => todo!(), - Expr::ByteArrayToBigInt(_) => todo!(), - Expr::LongToByteArray(_) => todo!(), - Expr::Collection(_) => todo!(), - Expr::Tuple(_) => todo!(), - Expr::CalcBlake2b256(_) => todo!(), - Expr::CalcSha256(_) => todo!(), - Expr::Context => todo!(), - Expr::Global => todo!(), - Expr::FuncValue(_) => todo!(), - Expr::Apply(_) => todo!(), - Expr::MethodCall(_) => todo!(), - Expr::PropertyCall(_) => todo!(), - Expr::If(_) => todo!(), - Expr::And(_) => todo!(), - Expr::Or(_) => todo!(), - Expr::Xor(_) => todo!(), - Expr::Atleast(_) => todo!(), - Expr::LogicalNot(_) => todo!(), - Expr::Negation(_) => todo!(), - Expr::BitInversion(_) => todo!(), - Expr::OptionGet(_) => todo!(), - Expr::OptionIsDefined(_) => todo!(), - Expr::OptionGetOrElse(_) => todo!(), - Expr::ExtractAmount(_) => todo!(), - Expr::ExtractRegisterAs(_) => todo!(), - Expr::ExtractBytes(_) => todo!(), - Expr::ExtractBytesWithNoRef(_) => todo!(), - Expr::ExtractScriptBytes(_) => todo!(), - Expr::ExtractCreationInfo(_) => todo!(), - Expr::ExtractId(_) => todo!(), - Expr::SizeOf(_) => todo!(), - Expr::Slice(_) => todo!(), - Expr::Fold(_) => todo!(), - Expr::Map(_) => todo!(), - Expr::Filter(_) => todo!(), - Expr::Exists(_) => todo!(), - Expr::ForAll(_) => todo!(), - Expr::SelectField(_) => todo!(), - Expr::BoolToSigmaProp(_) => todo!(), - Expr::Upcast(_) => todo!(), - Expr::Downcast(_) => todo!(), - Expr::CreateProveDlog(_) => todo!(), - Expr::CreateProveDhTuple(_) => todo!(), - Expr::SigmaPropBytes(_) => todo!(), - Expr::DecodePoint(_) => todo!(), - Expr::SigmaAnd(_) => todo!(), - Expr::SigmaOr(_) => todo!(), - Expr::GetVar(_) => todo!(), - Expr::DeserializeRegister(_) => todo!(), - Expr::DeserializeContext(_) => todo!(), - Expr::MultiplyGroup(_) => todo!(), - Expr::Exponentiate(_) => todo!(), - Expr::XorOf(_) => todo!(), - Expr::TreeLookup(_) => todo!(), - Expr::CreateAvlTree(_) => todo!(), + let input = self.input.print(w)?; + let offset = w.current_pos(); + write!(w, ".map(")?; + let mapper = self.mapper.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: Map::new(input, mapper).unwrap(), } + .into()) + } +} + +impl Print for Fold { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + let offset = w.current_pos(); + write!(w, ".fold(")?; + let zero = self.zero.print(w)?; + write!(w, ")(")?; + let fold_op = self.fold_op.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: Fold::new(input, zero, fold_op).unwrap(), + } + .into()) + } +} + +impl Print for FuncValue { + fn print(&self, w: &mut dyn Printer) -> Result { + writeln!(w, "{{")?; + w.inc_ident(); + writeln!( + w, + "({}) => ", + self.args() + .iter() + .map(|a| format!("{}", a)) + .collect::>() + .join(", ") + )?; + w.inc_ident(); + let body = self.body().print(w)?; + w.dec_ident(); + write!(w, "}}")?; + w.dec_ident(); + Ok(FuncValue::new(self.args().to_vec(), body).into()) + } +} + +impl Print for Filter { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + let offset = w.current_pos(); + write!(w, ".filter(")?; + let condition = self.condition.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: Filter::new(input, condition).unwrap(), + } + .into()) + } +} + +impl Print for If { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "if (")?; + let condition = self.condition.print(w)?; + write!(w, ") ")?; + let true_branch = self.true_branch.print(w)?; + write!(w, " else ")?; + let false_branch = self.false_branch.print(w)?; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(If { + condition: condition.into(), + true_branch: true_branch.into(), + false_branch: false_branch.into(), + } + .into()) + } +} + +impl Print for OptionIsDefined { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".isDefined()")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: OptionIsDefined { + input: Box::new(input), + }, + } + .into()) + } +} + +impl Print for ExtractRegisterAs { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".getReg")?; + write!(w, "({})", self.register_id)?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: ExtractRegisterAs::new( + input, + self.register_id, + SType::SOption(self.elem_tpe.clone().into()), + ) + .unwrap(), + } + .into()) + } +} + +impl Print for SelectField { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, "_{}", self.field_index)?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: SelectField::new(input, self.field_index).unwrap(), + } + .into()) + } +} + +impl Print for ExtractCreationInfo { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".creationInfo")?; + Ok(ExtractCreationInfo { + input: input.into(), + } + .into()) + } +} + +impl Print for PropertyCall { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let obj = self.obj.print(w)?; + write!(w, ".{}", self.method.name())?; + let length = w.current_pos() - offset; + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: PropertyCall { + obj: Box::new(obj), + method: self.method.clone(), + }, + } + .into()) + } +} + +impl Print for OptionGet { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".get")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: OptionGet::try_build(input).unwrap(), + } + .into()) + } +} + +impl Print for SizeOf { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".size")?; + Ok(SizeOf { + input: Box::new(input), + } + .into()) + } +} + +impl Print for Tuple { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "(")?; + let items = self.items.try_mapped_ref(|i| { + write!(w, ", ")?; + i.print(w) + })?; + write!(w, ")")?; + Ok(Tuple { items }.into()) } } From ec07000b6d63b08efd48e5963f5724f2ce1e9669 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 6 Sep 2023 11:13:03 +0300 Subject: [PATCH 58/74] add Print impl for various IR nodes and print EIP23 refresh contract; --- ergotree-ir/src/pretty_printer.rs | 86 ++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 124 +++++++++++++++++++++--- 2 files changed, 197 insertions(+), 13 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index dda02ba18..107e75919 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -16,6 +16,10 @@ pub trait Printer: Write { fn dec_ident(&mut self); /// Get current indent fn get_indent(&self) -> usize; + /// Print the current indent + fn print_indent(&mut self) -> std::fmt::Result { + write!(self, "{:indent$}", "", indent = self.get_indent()) + } } /// Printer implementation with tracking of current position and indent @@ -203,6 +207,88 @@ mod tests { check_pretty( ergo_tree.proposition().unwrap(), expect![[r#" + { + val v1 = HEIGHT - 30 + val v2 = INPUTS(0) + val v3 = INPUTS.filter({ + (v3: Box) => + if (v3.getReg(6).isDefined()) v3.creationInfo._1 >= v1 && v3.tokens(0)._1 == "2a472d4a614e645267556b58703273357638792f423f4528482b4d6250655368" && v3.getReg(5).get == v2.getReg(5).get else false + } + ) + val v4 = v3.size + val v5 = v3.fold((, 1, (, true, 0)))({ + (v5: ((Long, (Boolean, Long)), Box)) => + { + val v7 = v5._2.getReg(6).get + val v8 = v5._1 + val v9 = v8._2 + (, v7, (, v9._1 && v8._1 <= v7, v9._2 + v7)) + } + + } + ) + val v6 = v5._2 + val v7 = v5._1 + val v8 = v2.tokens + val v9 = v8(0) + val v10 = OUTPUTS(0) + val v11 = v10.tokens + val v12 = v11(1) + val v13 = v8(1) + val v14 = OUTPUTS(1) + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + allOf( + proveDlog(v3(getVar(0).get).getReg(4).get), + sigmaProp(v2.creationInfo._1 < v1), + ), + sigmaProp(v4 >= 4), + ), + sigmaProp(v6._1), + ), + sigmaProp(v7 - v3(0).getReg(6).get <= v7 * upcast(5) / 100), + ), + sigmaProp(v9._1 == "472b4b6250655368566d597133743677397a24432646294a404d635166546a57"), + ), + sigmaProp(v11(0) == v9), + ), + sigmaProp(v12._1 == v13._1), + ), + sigmaProp(v12._2 >= v13._2 - upcast(v4 * 2)), + ), + sigmaProp(v11.size == v8.size), + ), + sigmaProp(v10.getReg(4).get == v6._2 / upcast(v4)), + ), + sigmaProp(v10.getReg(5).get == v2.getReg(5).get + 1), + ), + sigmaProp(v10.propBytes == v2.propBytes), + ), + sigmaProp(v10.value >= v2.value), + ), + sigmaProp(v10.creationInfo._1 >= HEIGHT - 4), + ), + sigmaProp(v14.tokens == SELF.tokens), + ), + sigmaProp(v14.propBytes == SELF.propBytes), + ), + sigmaProp(v14.value >= SELF.value), + ) + } "#]], ) } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 4a69d8476..f336c56ce 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -2,6 +2,7 @@ use thiserror::Error; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; +use crate::mir::bool_to_sigma::BoolToSigmaProp; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::coll_filter::Filter; @@ -9,18 +10,24 @@ use crate::mir::coll_fold::Fold; use crate::mir::coll_map::Map; use crate::mir::coll_size::SizeOf; use crate::mir::constant::Constant; +use crate::mir::create_provedlog::CreateProveDlog; use crate::mir::expr::Expr; +use crate::mir::extract_amount::ExtractAmount; use crate::mir::extract_creation_info::ExtractCreationInfo; use crate::mir::extract_reg_as::ExtractRegisterAs; +use crate::mir::extract_script_bytes::ExtractScriptBytes; use crate::mir::func_value::FuncValue; +use crate::mir::get_var::GetVar; use crate::mir::global_vars::GlobalVars; use crate::mir::if_op::If; use crate::mir::option_get::OptionGet; use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; use crate::mir::select_field::SelectField; +use crate::mir::sigma_and::SigmaAnd; use crate::mir::tuple::Tuple; use crate::mir::unary_op::OneArgOpTryBuild; +use crate::mir::upcast::Upcast; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; use crate::source_span::SourceSpan; @@ -81,11 +88,11 @@ impl Print for Expr { Expr::OptionGet(v) => v.expr().print(w), Expr::OptionIsDefined(v) => v.expr().print(w), Expr::OptionGetOrElse(_) => todo!(), - Expr::ExtractAmount(_) => todo!(), + Expr::ExtractAmount(v) => v.print(w), Expr::ExtractRegisterAs(v) => v.expr().print(w), Expr::ExtractBytes(_) => todo!(), Expr::ExtractBytesWithNoRef(_) => todo!(), - Expr::ExtractScriptBytes(_) => todo!(), + Expr::ExtractScriptBytes(v) => v.print(w), Expr::ExtractCreationInfo(v) => v.print(w), Expr::ExtractId(_) => todo!(), Expr::SizeOf(v) => v.print(w), @@ -96,16 +103,16 @@ impl Print for Expr { Expr::Exists(_) => todo!(), Expr::ForAll(_) => todo!(), Expr::SelectField(v) => v.expr().print(w), - Expr::BoolToSigmaProp(_) => todo!(), - Expr::Upcast(_) => todo!(), + Expr::BoolToSigmaProp(v) => v.print(w), + Expr::Upcast(v) => v.print(w), Expr::Downcast(_) => todo!(), - Expr::CreateProveDlog(_) => todo!(), + Expr::CreateProveDlog(v) => v.print(w), Expr::CreateProveDhTuple(_) => todo!(), Expr::SigmaPropBytes(_) => todo!(), Expr::DecodePoint(_) => todo!(), - Expr::SigmaAnd(_) => todo!(), + Expr::SigmaAnd(v) => v.print(w), Expr::SigmaOr(_) => todo!(), - Expr::GetVar(_) => todo!(), + Expr::GetVar(v) => v.expr().print(w), Expr::DeserializeRegister(_) => todo!(), Expr::DeserializeContext(_) => todo!(), Expr::MultiplyGroup(_) => todo!(), @@ -122,18 +129,19 @@ impl Print for BlockValue { let offset = w.current_pos(); writeln!(w, "{{")?; w.inc_ident(); - let indent = w.get_indent(); let mut items = Vec::new(); for item in &self.items { - write!(w, "{:indent$}", "", indent = indent)?; + w.print_indent()?; items.push(item.print(w)?); writeln!(w)?; } // indent for result - write!(w, "{:indent$}", "", indent = indent)?; + w.print_indent()?; let res = self.result.print(w)?; + writeln!(w)?; w.dec_ident(); - writeln!(w, "\n}}")?; + w.print_indent()?; + writeln!(w, "}}")?; let length = w.current_pos() - offset; Ok(Spanned { source_span: SourceSpan { offset, length }, @@ -265,7 +273,9 @@ impl Print for Fold { let zero = self.zero.print(w)?; write!(w, ")(")?; let fold_op = self.fold_op.print(w)?; + w.print_indent()?; write!(w, ")")?; + w.dec_ident(); let length = w.current_pos() - offset; #[allow(clippy::unwrap_used)] // we only added spans Ok(Spanned { @@ -278,8 +288,10 @@ impl Print for Fold { impl Print for FuncValue { fn print(&self, w: &mut dyn Printer) -> Result { + w.inc_ident(); writeln!(w, "{{")?; w.inc_ident(); + w.print_indent()?; writeln!( w, "({}) => ", @@ -290,9 +302,12 @@ impl Print for FuncValue { .join(", ") )?; w.inc_ident(); + w.print_indent()?; let body = self.body().print(w)?; w.dec_ident(); - write!(w, "}}")?; + writeln!(w)?; + w.print_indent()?; + writeln!(w, "}}")?; w.dec_ident(); Ok(FuncValue::new(self.args().to_vec(), body).into()) } @@ -304,7 +319,9 @@ impl Print for Filter { let offset = w.current_pos(); write!(w, ".filter(")?; let condition = self.condition.print(w)?; + w.print_indent()?; write!(w, ")")?; + w.dec_ident(); let length = w.current_pos() - offset; #[allow(clippy::unwrap_used)] // we only added spans Ok(Spanned { @@ -375,7 +392,7 @@ impl Print for SelectField { fn print(&self, w: &mut dyn Printer) -> Result { let offset = w.current_pos(); let input = self.input.print(w)?; - write!(w, "_{}", self.field_index)?; + write!(w, "._{}", self.field_index)?; let length = w.current_pos() - offset; #[allow(clippy::unwrap_used)] // we only added spans Ok(Spanned { @@ -451,3 +468,84 @@ impl Print for Tuple { Ok(Tuple { items }.into()) } } + +impl Print for SigmaAnd { + fn print(&self, w: &mut dyn Printer) -> Result { + writeln!(w, "allOf(")?; + let items = self.items.try_mapped_ref(|i| -> Result { + w.inc_ident(); + w.print_indent()?; + let item = i.print(w)?; + write!(w, ", ")?; + writeln!(w)?; + w.dec_ident(); + Ok(item) + })?; + w.print_indent()?; + write!(w, ")")?; + Ok(SigmaAnd { items }.into()) + } +} + +impl Print for CreateProveDlog { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "proveDlog(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(CreateProveDlog { + input: Box::new(input), + } + .into()) + } +} + +impl Print for GetVar { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "getVar({})", self.var_id)?; + Ok(self.clone().into()) + } +} + +impl Print for BoolToSigmaProp { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "sigmaProp(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(BoolToSigmaProp { + input: Box::new(input), + } + .into()) + } +} + +impl Print for Upcast { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "upcast(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Upcast::new(input, self.tpe.clone()).unwrap().into()) + } +} + +impl Print for ExtractScriptBytes { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".propBytes")?; + Ok(ExtractScriptBytes { + input: Box::new(input), + } + .into()) + } +} + +impl Print for ExtractAmount { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".value")?; + Ok(ExtractAmount { + input: Box::new(input), + } + .into()) + } +} From b55a0b307d058b7dd254b983d163abd0783f1d47 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 Sep 2023 12:48:58 +0300 Subject: [PATCH 59/74] add EIP23 update contract as pretty printer test; --- ergotree-ir/src/pretty_printer.rs | 40 +++++++++++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 29 ++++++++++++++++-- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 107e75919..a8ddfb338 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -292,4 +292,44 @@ mod tests { "#]], ) } + + #[test] + fn eip23_update_contract() { + let ergo_tree_bytes = base16::decode("100f0400040004000402040204020e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570400040004000e203f4428472d4b6150645367566b5970337336763979244226452948404d625165010005000400040cd80ad601b2a4730000d602db63087201d603b27202730100d604b2a5730200d605db63087204d606b2a5730300d607b27205730400d6088c720701d6098c720702d60ab27202730500d1ededed938c7203017306edededed937203b2720573070093c17201c1720493c672010405c67204040593c672010504c672040504efe6c672040661edededed93db63087206db6308a793c27206c2a792c17206c1a7918cc77206018cc7a701efe6c67206046192b0b5a4d9010b63d801d60ddb6308720b9591b1720d7308d801d60ec6720b070eededed938cb2720d73090001730a93e4c6720b05048cc7a70193e4c6720b060ecbc2720495ede6720ee6c6720b0805ed93e4720e720893e4c6720b08057209ed938c720a017208938c720a027209730b730cd9010b41639a8c720b018cb2db63088c720b02730d00027e730e05").unwrap(); + let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap(); + check_pretty( + ergo_tree.proposition().unwrap(), + expect![[r#" + { + val v1 = INPUTS(0) + val v2 = v1.tokens + val v3 = v2(0) + val v4 = OUTPUTS(0) + val v5 = v4.tokens + val v6 = OUTPUTS(1) + val v7 = v5(1) + val v8 = v7._1 + val v9 = v7._2 + val v10 = v2(1) + sigmaProp(v3._1 == "472b4b6250655368566d597133743677397a24432646294a404d635166546a57" && v3 == v5(0) && v1.value == v4.value && v1.getReg(4) == v4.getReg(4) && v1.getReg(5) == v4.getReg(5) && !v4.getReg(6).isDefined() && v6.tokens == SELF.tokens && v6.propBytes == SELF.propBytes && v6.value >= SELF.value && v6.creationInfo._1 > SELF.creationInfo._1 && !v6.getReg(4).isDefined() && INPUTS.filter({ + (v11: Box) => + { + val v13 = v11.tokens + if (v13.size > 0) { + val v14 = v11.getReg(7) + v13(0)._1 == "3f4428472d4b6150645367566b5970337336763979244226452948404d625165" && v11.getReg(5).get == SELF.creationInfo._1 && v11.getReg(6).get == blake2b256(v4.propBytes) && if (v14.isDefined() && v11.getReg(8).isDefined()) v14.get == v8 && v11.getReg(8).get == v9 else v10._1 == v8 && v10._2 == v9 + } + else false + } + + } + ).fold(0)({ + (v11: (Long, Box)) => + v11._1 + v11._2.tokens(0)._2 + } + ) >= upcast(6)) + } + "#]], + ) + } } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index f336c56ce..85f8b05bb 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -3,6 +3,7 @@ use thiserror::Error; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::bool_to_sigma::BoolToSigmaProp; +use crate::mir::calc_blake2b256::CalcBlake2b256; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::coll_filter::Filter; @@ -20,6 +21,7 @@ use crate::mir::func_value::FuncValue; use crate::mir::get_var::GetVar; use crate::mir::global_vars::GlobalVars; use crate::mir::if_op::If; +use crate::mir::logical_not::LogicalNot; use crate::mir::option_get::OptionGet; use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; @@ -69,7 +71,7 @@ impl Print for Expr { Expr::LongToByteArray(_) => todo!(), Expr::Collection(_) => todo!(), Expr::Tuple(v) => v.print(w), - Expr::CalcBlake2b256(_) => todo!(), + Expr::CalcBlake2b256(v) => v.print(w), Expr::CalcSha256(_) => todo!(), Expr::Context => todo!(), Expr::Global => todo!(), @@ -82,7 +84,7 @@ impl Print for Expr { Expr::Or(_) => todo!(), Expr::Xor(_) => todo!(), Expr::Atleast(_) => todo!(), - Expr::LogicalNot(_) => todo!(), + Expr::LogicalNot(v) => v.print(w), Expr::Negation(_) => todo!(), Expr::BitInversion(_) => todo!(), Expr::OptionGet(v) => v.expr().print(w), @@ -549,3 +551,26 @@ impl Print for ExtractAmount { .into()) } } + +impl Print for LogicalNot { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "!")?; + let input = self.input.print(w)?; + Ok(LogicalNot { + input: Box::new(input), + } + .into()) + } +} + +impl Print for CalcBlake2b256 { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "blake2b256(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(CalcBlake2b256 { + input: Box::new(input), + } + .into()) + } +} From aa23f316e15c3167ea964a41f1fa87b056825f24 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 Sep 2023 12:54:39 +0300 Subject: [PATCH 60/74] add EIP23 ballot contract as pretty printer test; --- ergotree-ir/src/pretty_printer.rs | 20 ++++++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index a8ddfb338..e162b7f27 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -332,4 +332,24 @@ mod tests { "#]], ) } + + #[test] + fn eip23_ballot_contract() { + let ergo_tree_bytes = base16::decode("10070580dac409040204020400040204000e206251655468576d5a7134743777217a25432a462d4a404e635266556a586e3272d803d601e4c6a70407d602b2a5e4e3000400d603c672020407eb02cd7201d1edededede6720393c27202c2a793db63087202db6308a792c172027300ededededed91b1a4730191b1db6308b2a47302007303938cb2db6308b2a473040073050001730693e47203720192c17202c1a7efe6c672020561").unwrap(); + let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap(); + check_pretty( + ergo_tree.proposition().unwrap(), + expect![[r#" + { + val v1 = SELF.getReg(4).get + val v2 = OUTPUTS(getVar(0).get) + val v3 = v2.getReg(4) + anyOf( + proveDlog(v1), + sigmaProp(v3.isDefined() && v2.propBytes == SELF.propBytes && v2.tokens == SELF.tokens && v2.value >= 10000000 && INPUTS.size > 1 && INPUTS(1).tokens.size > 0 && INPUTS(1).tokens(0)._1 == "6251655468576d5a7134743777217a25432a462d4a404e635266556a586e3272" && v3.get == v1 && v2.value >= SELF.value && !v2.getReg(5).isDefined()), + ) + } + "#]], + ) + } } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 85f8b05bb..4d9f92d6a 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -27,6 +27,7 @@ use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; use crate::mir::select_field::SelectField; use crate::mir::sigma_and::SigmaAnd; +use crate::mir::sigma_or::SigmaOr; use crate::mir::tuple::Tuple; use crate::mir::unary_op::OneArgOpTryBuild; use crate::mir::upcast::Upcast; @@ -113,7 +114,7 @@ impl Print for Expr { Expr::SigmaPropBytes(_) => todo!(), Expr::DecodePoint(_) => todo!(), Expr::SigmaAnd(v) => v.print(w), - Expr::SigmaOr(_) => todo!(), + Expr::SigmaOr(v) => v.print(w), Expr::GetVar(v) => v.expr().print(w), Expr::DeserializeRegister(_) => todo!(), Expr::DeserializeContext(_) => todo!(), @@ -489,6 +490,24 @@ impl Print for SigmaAnd { } } +impl Print for SigmaOr { + fn print(&self, w: &mut dyn Printer) -> Result { + writeln!(w, "anyOf(")?; + let items = self.items.try_mapped_ref(|i| -> Result { + w.inc_ident(); + w.print_indent()?; + let item = i.print(w)?; + write!(w, ", ")?; + writeln!(w)?; + w.dec_ident(); + Ok(item) + })?; + w.print_indent()?; + write!(w, ")")?; + Ok(SigmaOr { items }.into()) + } +} + impl Print for CreateProveDlog { fn print(&self, w: &mut dyn Printer) -> Result { write!(w, "proveDlog(")?; From 1456b1d082bae44e3a4ffc23b6a818a8bf8ee5ff Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 Sep 2023 12:56:28 +0300 Subject: [PATCH 61/74] add EIP23 oracle contract as pretty printer test; --- ergotree-ir/src/pretty_printer.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index e162b7f27..d3a96ce84 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -352,4 +352,28 @@ mod tests { "#]], ) } + + #[test] + fn eip23_oracle_contract() { + let ergo_tree_bytes = base16::decode("100a040004000580dac409040004000e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570402040204020402d804d601b2a5e4e3000400d602db63087201d603db6308a7d604e4c6a70407ea02d1ededed93b27202730000b2720373010093c27201c2a7e6c67201040792c172017302eb02cd7204d1ededededed938cb2db6308b2a4730300730400017305938cb27202730600018cb2720373070001918cb27202730800028cb272037309000293e4c672010407720492c17201c1a7efe6c672010561").unwrap(); + let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap(); + check_pretty( + ergo_tree.proposition().unwrap(), + expect![[r#" + { + val v1 = OUTPUTS(getVar(0).get) + val v2 = v1.tokens + val v3 = SELF.tokens + val v4 = SELF.getReg(4).get + allOf( + sigmaProp(v2(0) == v3(0) && v1.propBytes == SELF.propBytes && v1.getReg(4).isDefined() && v1.value >= 10000000), + anyOf( + proveDlog(v4), + sigmaProp(INPUTS(0).tokens(0)._1 == "472b4b6250655368566d597133743677397a24432646294a404d635166546a57" && v2(1)._1 == v3(1)._1 && v2(1)._2 > v3(1)._2 && v1.getReg(4).get == v4 && v1.value >= SELF.value && !v1.getReg(5).isDefined()), + ), + ) + } + "#]], + ) + } } From b81978cfd9952a4e5a75857a7f1ce65a7fd8b077 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 8 Sep 2023 14:56:34 +0300 Subject: [PATCH 62/74] add ageusd bank contract to pretty printer test --- ergotree-ir/src/pretty_printer.rs | 60 +++++++++++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 19 +++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index d3a96ce84..60c6d904f 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -90,6 +90,8 @@ mod tests { use expect_test::expect; + use crate::chain::address::AddressEncoder; + use crate::chain::address::NetworkPrefix; use crate::ergo_tree::ErgoTree; use crate::mir::bin_op::ArithOp; use crate::mir::bin_op::BinOp; @@ -376,4 +378,62 @@ mod tests { "#]], ) } + + #[test] + fn ageusd_bank_full() { + // from eip-15 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "MUbV38YgqHy7XbsoXWF5z7EZm524Ybdwe5p9WDrbhruZRtehkRPT92imXer2eTkjwPDfboa1pR3zb3deVKVq3H7Xt98qcTqLuSBSbHb7izzo5jphEpcnqyKJ2xhmpNPVvmtbdJNdvdopPrHHDBbAGGeW7XYTQwEeoRfosXzcDtiGgw97b2aqjTsNFmZk7khBEQywjYfmoDc9nUCJMZ3vbSspnYo3LarLe55mh2Np8MNJqUN9APA6XkhZCrTTDRZb1B4krgFY1sVMswg2ceqguZRvC9pqt3tUUxmSnB24N6dowfVJKhLXwHPbrkHViBv1AKAJTmEaQW2DN1fRmD9ypXxZk8GXmYtxTtrj3BiunQ4qzUCu1eGzxSREjpkFSi2ATLSSDqUwxtRz639sHM6Lav4axoJNPCHbY8pvuBKUxgnGRex8LEGM8DeEJwaJCaoy8dBw9Lz49nq5mSsXLeoC4xpTUmp47Bh7GAZtwkaNreCu74m9rcZ8Di4w1cmdsiK1NWuDh9pJ2Bv7u3EfcurHFVqCkT3P86JUbKnXeNxCypfrWsFuYNKYqmjsix82g9vWcGMmAcu5nagxD4iET86iE2tMMfZZ5vqZNvntQswJyQqv2Wc6MTh4jQx1q2qJZCQe4QdEK63meTGbZNNKMctHQbp3gRkZYNrBtxQyVtNLR8xEY8zGp85GeQKbb37vqLXxRpGiigAdMe3XZA4hhYPmAAU5hpSMYaRAjtvvMT3bNiHRACGrfjvSsEG9G2zY5in2YWz5X9zXQLGTYRsQ4uNFkYoQRCBdjNxGv6R58Xq74zCgt19TxYZ87gPWxkXpWwTaHogG1eps8WXt8QzwJ9rVx6Vu9a5GjtcGsQxHovWmYixgBU8X9fPNJ9UQhYyAWbjtRSuVBtDAmoV1gCBEPwnYVP5GCGhCocbwoYhZkZjFZy6ws4uxVLid3FxuvhWvQrVEDYp7WRvGXbNdCbcSXnbeTrPMey1WPaXX"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = CONTEXT.dataInputs + sigmaProp(if (v1.size > 0) { + val v2 = v1(0) + val v3 = v2.tokens(0)._1 == "011d3364de07e5a26f0c4eef0852cddb387039a921b7154ef3cab22c6eda887f" + val v4 = OUTPUTS(0) + val v5 = v4.value + val v6 = SELF.tokens + val v7 = v6(1) + val v8 = v7._2 + val v9 = v4.tokens + val v10 = v9(1) + val v11 = v10._2 + val v12 = v8 != v11 + val v13 = v6(0) + val v14 = v13._2 + val v15 = v9(0) + val v16 = v15._2 + val v17 = v14 != v16 + val v18 = SELF.getReg(5).get + val v19 = v4.getReg(5).get + val v20 = SELF.getReg(4).get + val v21 = v4.getReg(4).get + val v22 = OUTPUTS(1) + val v23 = v22.getReg(4).get + val v24 = if (v12) 0 else v23 + val v25 = if (v12) v23 else 0 + val v26 = SELF.value + val v27 = v22.getReg(5).get + val v28 = v2.getReg(4).get / 100 + val v29 = v26 min v20 * v28 max 0 + val v30 = if (v17) v28 min if (v20 == 0) 9223372036854775807 else v29 / v20 * v24 else { + val v30 = v26 - v29 + if (v30 == 0) 1000000 else if (v18 == 0) 1000000 else v30 / v18 * v25 + } + + val v31 = v30 * upcast(2) / 100 + val v32 = v21 * v28 + val v33 = if (HEIGHT > 460000) 800 else 1000000000 + val v34 = if (v32 == 0) v33 else v5 * 100 / v32 + v3 && v5 >= 10000000 && v4.propBytes == SELF.propBytes && v12 || v17 && !v12 && v17 && v8 + v18 == v11 + v19 && v14 + v20 == v16 + v21 && v20 + v24 == v21 && v18 + v25 == v19 && v26 + v27 == v5 && v21 >= 0 && v19 >= 0 && v15._1 == v13._1 && v10._1 == v7._1 && v9(2)._1 == v6(2)._1 && v27 == v30 + if (v31 < 0) -v31 else v31 && if (v17) if (v24 > 0) v34 >= 400 else true else if (v25 > 0) v34 <= v33 else v34 >= 400 && v3 + } + else false || INPUTS(0).tokens(0)._1 == "239c170b7e82f94e6b05416f14b8a2a57e0bfff0e3c93f4abbcd160b6a5b271a") + } + "#]], + ) + } } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 4d9f92d6a..c290f6934 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -22,6 +22,7 @@ use crate::mir::get_var::GetVar; use crate::mir::global_vars::GlobalVars; use crate::mir::if_op::If; use crate::mir::logical_not::LogicalNot; +use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::property_call::PropertyCall; @@ -74,7 +75,10 @@ impl Print for Expr { Expr::Tuple(v) => v.print(w), Expr::CalcBlake2b256(v) => v.print(w), Expr::CalcSha256(_) => todo!(), - Expr::Context => todo!(), + Expr::Context => { + write!(w, "CONTEXT")?; + Ok(self.clone()) + } Expr::Global => todo!(), Expr::FuncValue(v) => v.print(w), Expr::Apply(_) => todo!(), @@ -86,7 +90,7 @@ impl Print for Expr { Expr::Xor(_) => todo!(), Expr::Atleast(_) => todo!(), Expr::LogicalNot(v) => v.print(w), - Expr::Negation(_) => todo!(), + Expr::Negation(v) => v.expr().print(w), Expr::BitInversion(_) => todo!(), Expr::OptionGet(v) => v.expr().print(w), Expr::OptionIsDefined(v) => v.expr().print(w), @@ -593,3 +597,14 @@ impl Print for CalcBlake2b256 { .into()) } } + +impl Print for Negation { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "-")?; + let input = self.input.print(w)?; + Ok(Negation { + input: Box::new(input), + } + .into()) + } +} From 91c3cf4429395e6bec7866570177072ff0bd7820 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 8 Sep 2023 15:01:50 +0300 Subject: [PATCH 63/74] add ageusd update contract to pretty printer test; --- ergotree-ir/src/pretty_printer.rs | 34 +++++++++++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 14 +++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 60c6d904f..b3b2be8fc 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -436,4 +436,38 @@ mod tests { "#]], ) } + + #[test] + fn ageusd_update() { + // from eip-15 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "VLyjpv3dse3PbatT83GnDkBQasGqY52dAEdi9XpXhuSUn1FS1Tm7XxtAgmBiqY9pJXtEAsDKwX9ygSjrFu7vnUQZudhC2sSmxhxqgD3ZxJ2VsGwmPG77F6EiEZhcq71oqEq31y9XvCCXL5nqqszdENPAVhu7xT296qZ7w1x6hmwdh9ZE89bjfgbhfNYopoqsCaNLWYHJ12TDSY93kaGqCVKSu6gEF1gLpXBfRCnAPPxYswJPmK8oWDn8PKrUGs3MjVsj6bGXiW3VTGP4VsNH8YSSkjyj1FZ9azLsyfnNJ3zah2zUHdCCqY6PjH9JfHf9joCPf6TusvXgr71XWvh5e2HPEPQr4eJMD4S96cGTiSs3J5XcRd1tCDYoiis8nxv99zFFhHgpqXHgeqjhJ5sPot9eRYTsmm4cRTVLXYAiuKPS2qW5"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = INPUTS(1) + val v2 = v1.tokens + val v3 = OUTPUTS(1) + val v4 = SELF.id + val v5 = OUTPUTS(0) + sigmaProp(v2.size == 3 && v2(2)._1 == "7d672d1def471720ca5782fd6473e47e796d9ac0c138d9911346f118b2f6d9d9" && v2 == v3.tokens && v1.value == v3.value && v1.getReg(4).get == v3.getReg(4).get && v1.getReg(5).get == v3.getReg(5).get && v4 == INPUTS(0).id && SELF.tokens == v5.tokens && SELF.propBytes == v5.propBytes && v5.value >= SELF.value && INPUTS.filter({ + (v6: Box) => + { + val v8 = v6.tokens + v8.size > 0 && v8(0)._1 == "f7995f212216fcf21854f56df7a9a0a9fc9b7ae4c0f1cc40f5b406371286a5e0" && v6.getReg(6).get == v4 && v6.getReg(7).get == blake2b256(v3.propBytes) + } + + } + ).fold(0)({ + (v6: (Long, Box)) => + v6._1 + v6._2.tokens(0)._2 + } + ) >= upcast(3)) + } + "#]], + ) + } } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index c290f6934..a5057951f 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -15,6 +15,7 @@ use crate::mir::create_provedlog::CreateProveDlog; use crate::mir::expr::Expr; use crate::mir::extract_amount::ExtractAmount; use crate::mir::extract_creation_info::ExtractCreationInfo; +use crate::mir::extract_id::ExtractId; use crate::mir::extract_reg_as::ExtractRegisterAs; use crate::mir::extract_script_bytes::ExtractScriptBytes; use crate::mir::func_value::FuncValue; @@ -101,7 +102,7 @@ impl Print for Expr { Expr::ExtractBytesWithNoRef(_) => todo!(), Expr::ExtractScriptBytes(v) => v.print(w), Expr::ExtractCreationInfo(v) => v.print(w), - Expr::ExtractId(_) => todo!(), + Expr::ExtractId(v) => v.print(w), Expr::SizeOf(v) => v.print(w), Expr::Slice(_) => todo!(), Expr::Fold(v) => v.expr().print(w), @@ -608,3 +609,14 @@ impl Print for Negation { .into()) } } + +impl Print for ExtractId { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".id")?; + Ok(ExtractId { + input: Box::new(input), + } + .into()) + } +} From b1e4091e88366dbdba3b05bd65f6cd651e662fde Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 11 Sep 2023 15:21:22 +0300 Subject: [PATCH 64/74] add eip14 amm pool and swap contracts to pretty printer tests; --- ergotree-ir/src/pretty_printer.rs | 95 +++++++++++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 48 ++++++++++++- 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index b3b2be8fc..6d7ce761b 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -470,4 +470,99 @@ mod tests { "#]], ) } + + #[test] + fn ageusd_ballot() { + // from eip-15 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "22ELWBHzyWGjPRE48ZJDfFmD24myYdG3vHz8CipSS7rgE65ABmEj9QJiy3rG2PTJeCaZw9VX56GY6uoA3hQch7i5BfFU3AprUWTABi4X1VWtRdK9yrYJkmN6fq8hGfvmWTrsyh4fXZoGETpLuXQViYo194ajej2h7dr3oqNATdMskSXzxJi83bFdAvQ"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = OUTPUTS(INPUTS.indexOf(SELF0)) + val v2 = SELF.getReg(4).get + allOf( + sigmaProp(v1.getReg(4).get == v2 && v1.propBytes == SELF.propBytes && v1.tokens == SELF.tokens && v1.value >= SELF.value), + anyOf( + proveDlog(v2), + sigmaProp(INPUTS(0).tokens(0)._1 == "239c170b7e82f94e6b05416f14b8a2a57e0bfff0e3c93f4abbcd160b6a5b271a" && !v1.getReg(7).isDefined()), + ), + ) + } + "#]], + ) + } + + #[test] + fn amm_simple_pool() { + // from eip-14 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "k6fD5ht5e1itDejPFV2VzAoHv478KQCbDnLAL6XUVeEu8KDaboCVZAoFz2AtMoLqM3CgQfr2TZhpwz7K96AgwTXDvBVeTchJ31jjD46Di1W67H8wwFcivnY62UB6L7HWzCkbYuiZaAq2qSJta5Twt4A2Aaoy7xViWcyLUVNAyQYDJXKhVBAGwp76i2too5yWUmEU4zt9XnjJAUt1FFfurNtTNHNPDbqmTRE4crz347q6rfbvkMmg9Jtk9rSiPCQpKjdbZVzUnP4CUw6AvQH6rZXxgNMktAtjQdHhCnrCmf78FwCKqYS54asKd1MFgYNT4NzPwmdZF6JtQt1vvkjZXqpGkjy33xxDNYy8JZS8eeqVgZErPeJ1aj4aaK8gvmApUgGStMDFeFYjuQqZiZxEAHNdAXDg7hyGnmfzA6Hj9zcB7p9nKCDNhEQEMPL1kMG5aXvt2HUPXqiCkLrv596DaGmRMN3gMJaj1T1AfMYNwZozcJ9uUSK4i6Xham28HWAekTtDPhobnmjvkubwLVTtvUumWHtDWFxYSJPF7vqzgZqg6Y5unMF"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = OUTPUTS(0) + val v2 = v1.tokens + val v3 = SELF.tokens + val v4 = v2(0) + val v5 = v3(0) + val v6 = v2(2) + val v7 = v3(2) + val v8 = v2(3) + val v9 = v3(3) + val v10 = 1000000000000000000 - v5._2 + val v11 = 1000000000000000000 - v4._2 - v10 + val v12 = v7._2 + val v13 = v6._2 - v12 + val v14 = v13 > 0 + val v15 = v9._2 + val v16 = upcast(v15) + val v17 = upcast(v13) + val v18 = v8._2 - v15 + val v19 = upcast(v12) + val v20 = upcast(v18) + val v21 = upcast(v10) + val v22 = upcast(v11) / v21 + sigmaProp(v1.propBytes == SELF.propBytes && v1.value >= SELF.value && v2(1) == v3(1) && v4._1 == v5._1 && v6._1 == v7._1 && v8._1 == v9._1 && if (v11 == 0) if (v14) v16 * v17 * BigInt256(Int256(997)) >= upcast(-v18) * v19 * BigInt256(Int256(1000)) + upcast(v13 * 997) else v19 * v20 * BigInt256(Int256(997)) >= upcast(-v13) * v16 * BigInt256(Int256(1000)) + upcast(v18 * 997) else if (v14 && v18 > 0) upcast(-v11) <= v17 * v21 / v19 min v20 * v21 / v16 else v17 >= v22 * v19 && v20 >= v22 * v16) + } + "#]], + ) + } + + #[test] + fn amm_simple_swap() { + // from eip-14 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "cLPHJ3MHuKAHoCUwGhcEFw5sWJqvPwFyKxTRj1aUoMwgAz78Fg3zLXRhBup9Te1WLau1gZXNmXvUmeXGCd7QLeqB7ArrT3v5cg26piEtqymM6j2SkgYVCobgoAGKeTf6nMLxv1uVrLdjt1GnPxG1MuWj7Es7Dfumotbx9YEaxwqtTUC5SKsJc9LCpAmNWRAQbU6tVVEvmfwWivrGoZ3L5C4DMisxN3U"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = INPUTS(0).tokens + val v2 = v1(2) + val v3 = SELF.tokens(0) + val v4 = v3._1 + val v5 = v1(3) + val v6 = v3._2 + sigmaProp(v2._1 == v4 || v5._1 == v4 && OUTPUTS.exists({ + (v7: Box) => + { + val v9 = v7.tokens(0)._2 + v9 >= upcast(1000) && upcast(v5._2) * upcast(v6) * BigInt256(Int256(997)) <= upcast(v9) * upcast(v2._2) * BigInt256(Int256(1000)) + upcast(v6 * 997) + } + + } + )) + } + "#]], + ) + } } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index a5057951f..17df1935c 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -6,6 +6,7 @@ use crate::mir::bool_to_sigma::BoolToSigmaProp; use crate::mir::calc_blake2b256::CalcBlake2b256; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; +use crate::mir::coll_exists::Exists; use crate::mir::coll_filter::Filter; use crate::mir::coll_fold::Fold; use crate::mir::coll_map::Map; @@ -23,6 +24,7 @@ use crate::mir::get_var::GetVar; use crate::mir::global_vars::GlobalVars; use crate::mir::if_op::If; use crate::mir::logical_not::LogicalNot; +use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; use crate::mir::option_is_defined::OptionIsDefined; @@ -83,7 +85,7 @@ impl Print for Expr { Expr::Global => todo!(), Expr::FuncValue(v) => v.print(w), Expr::Apply(_) => todo!(), - Expr::MethodCall(_) => todo!(), + Expr::MethodCall(v) => v.expr().print(w), Expr::PropertyCall(v) => v.expr().print(w), Expr::If(v) => v.print(w), Expr::And(_) => todo!(), @@ -108,7 +110,7 @@ impl Print for Expr { Expr::Fold(v) => v.expr().print(w), Expr::Map(v) => v.expr().print(w), Expr::Filter(v) => v.expr().print(w), - Expr::Exists(_) => todo!(), + Expr::Exists(v) => v.expr().print(w), Expr::ForAll(_) => todo!(), Expr::SelectField(v) => v.expr().print(w), Expr::BoolToSigmaProp(v) => v.print(w), @@ -273,6 +275,23 @@ impl Print for Map { } } +impl Print for Exists { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + let offset = w.current_pos(); + write!(w, ".exists(")?; + let condition = self.condition.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: Exists::new(input, condition).unwrap(), + } + .into()) + } +} + impl Print for Fold { fn print(&self, w: &mut dyn Printer) -> Result { let input = self.input.print(w)?; @@ -439,6 +458,31 @@ impl Print for PropertyCall { } } +impl Print for MethodCall { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let obj = self.obj.print(w)?; + write!(w, ".{}", self.method.name())?; + write!(w, "(")?; + let args = self + .args + .iter() + .map(|a| -> Result { a.print(w) }) + .collect::, _>>()?; + write!(w, ")")?; + let length = w.current_pos() - offset; + Ok(Spanned { + source_span: SourceSpan { offset, length }, + expr: MethodCall { + obj: Box::new(obj), + method: self.method.clone(), + args, + }, + } + .into()) + } +} + impl Print for OptionGet { fn print(&self, w: &mut dyn Printer) -> Result { let offset = w.current_pos(); From 4d09d26dd190b17e68cfaa1218565a75a65a7523 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 13 Sep 2023 13:29:25 +0300 Subject: [PATCH 65/74] add the rest of amm_conc_pool_* EIP22 auction contracts to the pretty printer tests; --- ergotree-ir/src/mir/collection.rs | 4 + ergotree-ir/src/pretty_printer.rs | 166 ++++++++++++++++++++++++ ergotree-ir/src/pretty_printer/print.rs | 62 ++++++++- 3 files changed, 229 insertions(+), 3 deletions(-) diff --git a/ergotree-ir/src/mir/collection.rs b/ergotree-ir/src/mir/collection.rs index 82f650e10..b314243af 100644 --- a/ergotree-ir/src/mir/collection.rs +++ b/ergotree-ir/src/mir/collection.rs @@ -51,6 +51,10 @@ impl Collection { } } + pub fn from_bools(bools: Vec) -> Self { + Collection::BoolConstants(bools) + } + /// Type pub fn tpe(&self) -> SType { SType::SColl( diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index 6d7ce761b..dbada114a 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -565,4 +565,170 @@ mod tests { "#]], ) } + + #[test] + fn amm_conc_pool_root() { + // from eip-14 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "3STRfQWC9Xb5wAxBiEQ74uTFSemk1oHn43mwj9tMCeu2a3A4kie1bY2qsCdRaEmdQoq3B4tXQuzq9nm84A8PmBgCzgGDEZf2pgYoAUc6krZxUY3rvKWW44ZpzN3u5bFRpKDo6rxKtxX2tw99xmfyfaVBejgDaTfsib2PSVsu9hrLQ3SouECWHQMjDA3Pi8ZuCvQeW8GDkZfHPr3SgwaxY1jpY2njsmf3JBASMoVZ6Mfpg63Q6mBno7mKUSCE7vNHHUZe2V7JEikwjPkaxSWxnwy3J17faGtiEHZLKiNQ9WNtsJLbdVp56dQGfC2zaiXjhx1XJK6m4Nh2M8yEvSuBzanRBAJqrNseGS97tk2iLqqfHrqqmmDsHY3mujCURky4SLr7YLk4B"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = OUTPUTS(0) + val v2 = SELF.tokens(0) + val v3 = v2._1 + val v4 = SELF.getReg(4).get + val v5 = SELF.getReg(5).get + val v6 = SELF.getReg(6).get + val v7 = OUTPUTS(1) + val v8 = v7.tokens + val v9 = v7.getReg(6).get + val v10 = v5._2 + val v11 = v5._1 + val v12 = v7.getReg(5).get + val v13 = v7.getReg(7).get + sigmaProp(v1.propBytes == SELF.propBytes && v1.value >= SELF.value && v1.tokens(0) == (, v3, v2._2 - 1) && v1.getReg(4).get == v4 && v1.getReg(5).get == v5 && v1.getReg(6).get == v6 && v7.getReg(4).get == v4 && v7.getReg(8).get == v6 && v8(1)._1 == v3 && v8(0) == (, SELF.id, 1000000000000000000) && v9._1 * v10 == v9._2 * v11 * v12 && v13._1 * v10 == v13._2 * v11 * v12 + 1) + } + "#]], + ) + } + + #[test] + fn amm_conc_pool_boot() { + // from eip-14 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "6Mv73vd1MnJp6AQg5vHGP9nujFc3Y1PL5gzeUt9PzCaUiQug7ueQGU1bDkmFkCspq4LU8j3T8yY6UyJQKSfah5qEDzjx8QCJF47NBG5jxgPxmBHkM6cUgnYa5ngzn9jrpAn379UC7o5nugTg3HYWZGk3APMcRftkrC3EgroiVMEmSkDcDwaebkNWKfKe3JXgewoTrgZ2YLMafr3JfX47C1zddoWDhS8TWryQYEprkP334eisuh1Fr2iNTW9ruV6m38cRkfRfzSBHYq45mvNLH7JQo6uQZ4NFPx4t27Q5A3mSqCpk7ATThFcQmc2w3Pp2F6xL87c94gxk83G8UEqkAhmaNfoj19zji9rxqRzq9gJeTLBraHR2DchKtahH8HhFPg5DZ4SjwJ4MHqTDF"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = OUTPUTS(0) + val v2 = v1.tokens + val v3 = SELF.tokens + val v4 = v1.getReg(5).get + val v5 = v1.getReg(6).get + val v6 = v2(3) + val v7 = v6._2 + val v8 = upcast(v7) + val v9 = v1.getReg(7).get + val v10 = upcast(v9) + val v11 = v2(2) + val v12 = v3(0) + sigmaProp(true && v1.value >= SELF.value && v2(0) == (, SELF.id, 1) && v2(1) == (, v3(1)._1, 1) && v1.getReg(4).get == SELF.getReg(4).get && v4 == SELF.getReg(6).get && v5 == SELF.getReg(7).get && (, v6._1, v2(4)._1) == SELF.getReg(8).get && v8 * v8 == v10 * v10 && if (v11._1 == v12._1) v11._2 else 0 >= v12._2 - v9 && v7 * upcast(v4._2) >= v7 * upcast(v4._1) && v7 * upcast(v5._2) < v7 * upcast(v5._1)) + } + "#]], + ) + } + +#[test] + fn amm_conc_pool() { + // from eip-14 https://github.com/ergoplatform/eips/pull/27/files + let p2s_addr_str = "AhCu1UkNT4c9q3B2Lb7gNgvZWCdXL8iYgmNxTYiy4S3wgKWFFW6kz9v7pvY8NqC7g4wgXXwzJY1fQVn2xrLkiyiQWsorq5dR7d5KnDAY43H4GvSVjaDciadXCSHCb8jgk8mFSQCwoZHweLmMJ25312wT85AySJgYUuzdUxMz4EnQpiwZR2XVZq3M81gycuqP9gUryryjN4J1cAF3yL3kZR3rREubBvJ2CY5hF74Xaj2jwajivkESkqq22ieWWG2sK7dk1A7KHr1MmiXGcUBAMMGPAu3mVCeFW9SongxP9hodnJThLknjWRBBBC6wq5jNkSdHrMbdaQM3XesXqGTk9KwWpnSL92E96muU2k8FQbo5isps1r5ciYVrFptfEAC3tWbwcVmRKtrgxtCex6bP5aBZYjaH6L9QQbkYriDAcQ1iZcpf3hHCqURjRXL7i72C3aGBwzzspQvhLof6x4f4gPxTCtF1bNUxddUL6DJ1PbQWzVH8taivjhHohis6sRn3Akvv4xaZRJdKZ8rDuiounRKNXi8VoNgVEZbSFYtfweRSdsiXJCkhtehLWdtFTk1eg7djASdBGKaguvtEBcGaAALVDUoH479VskPUQ6hrfS7KcWrATBdb8sf4W5MFpx7UNitzq2fzSKC96mQRUzy5uELe7Y7vexm5ArNEyr6ARkypZypSzJ2CEifjVxxRBEWVtbdqHrwP4gWv6cMdbqFWwuXAw2BZQnWpZFtKAGQ9m"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = OUTPUTS(0) + val v2 = v1.tokens + val v3 = SELF.tokens + val v4 = v2(2) + val v5 = v3(2) + val v6 = v2(3) + val v7 = v3(3) + val v8 = v2(4) + val v9 = v3(4) + val v10 = SELF.getReg(4).get + val v11 = SELF.getReg(5).get + val v12 = SELF.getReg(6).get + val v13 = 1000000000000000000 - v5._2 + val v14 = 1000000000000000000 - v4._2 - v13 + val v15 = v6._2 + val v16 = upcast(v15) + val v17 = v8._2 + val v18 = upcast(v17) + val v19 = v16 * upcast(v11._2) >= v18 * upcast(v11._1) && v16 * upcast(v12._2) < v18 * upcast(v12._1) + val v20 = v7._2 + val v21 = v15 - v20 + val v22 = v21 > 0 + val v23 = v9._2 + val v24 = upcast(v23) + val v25 = upcast(v21) + val v26 = v17 - v23 + val v27 = upcast(v20) + val v28 = 1000 + val v29 = upcast(v26) + val v30 = upcast(v13) + val v31 = upcast(v14) / v30 + sigmaProp(v1.propBytes == SELF.propBytes && v1.value >= SELF.value && v2(0) == v3(0) && v2(1) == v3(1) && v4._1 == v5._1 && v6._1 == v7._1 && v8._1 == v9._1 && v1.getReg(4).get == v10 && v1.getReg(5).get == v11 && v1.getReg(6).get == v12 && if (v14 == 0) if (v22) v24 * v25 * upcast(v10) >= upcast(-v26) * v27 * upcast(v28) + upcast(v21 * upcast(v10)) else v27 * v29 * upcast(v10) >= upcast(-v21) * v24 * upcast(v28) + upcast(v26 * upcast(v10)) && v19 else if (v22 && v26 > 0) upcast(-v14) <= v25 * v30 / v27 min v29 * v30 / v24 && v19 else v25 >= v31 * v27 && v29 >= v31 * v24) + } + "#]], + ) + } + +#[test] + fn eip_22_auction() { + // from https://github.com/ergoplatform/eips/blob/adbe21512cadf51a2d9af8406cfd418f95335899/eip-0022.md + let p2s_addr_str = "GE68RH3VEgW6b4kN3GhYigrLxoXr9jMgMpmm3KnXJaYq1PzHieYhz7Uka86idxvBWLRLmpiA3HrxHPsX1jzQZEv5yaRDueiJqks1keM7iB1eYWMEVRUUq1MLFzdA1FHQwCfSakM3Uc8uBPqk2icxhoXvw1CVbUVtFCzcPrZzf8Jjf8gS5bCFpWQscHo14HTsdBxyV3dwL6wKu8LP8FuWJE7qCEgX9ToEiztH4ZLmFwBejnUFrCQqjLVLWpdgdnAXVyewiX9DxXKJKL4wNqhPUrYjmHEVvpZAezXjzfVMr7gKupTqAgx2AJYGh4winEDeYq9MVshX8xjJweGhbAm2RXN1euQpoepFaKqfrT2mQBTmr6edbbzYg6VJ7DoSCDzmcUupFAmZMjMiaUbgtyz2VEbPEKsmAFrZ6zdB5EUxhiYZMd6KdstsJwZCgKJSSCShTgpfqNLCdpR9JbZFQpA1uhUkuLMPvGi74V5EwijTEEtjmTVcWcVhJKv4GDr1Lqe2bMPq4jfEfqvemaY8FcrCsCSi2LZoQUeJ9VrBeotGTKccq8JhwnvNGhLUUrrm32v3bhU82jbtVBVFRD3FSv5hhS6pKHtTevjwuG7JWoR3LN7279A7zQGJWmkSWDoEhHjgxseqZ2G5bLB7ZVEzKM261QhwMwmXA1eWgq8zdBH1u9kFC9bMQ812q2DPZTuhzpBWJh74UGwaEgZLhnUrDKT58cEa4R3kfWyGCMoNw78q1E3a2eKDz8Va5wnixzT2SZFHU8DfHjPSz5rm8Mr3YxgRC6GzaasPDxTrZjuMJHU2exhqsoFvur7Q"; + let encoder = AddressEncoder::new(NetworkPrefix::Mainnet); + let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap(); + let expr = addr.script().unwrap().proposition().unwrap(); + check_pretty( + expr, + expect![[r#" + { + val v1 = OUTPUTS(0) + val v2 = CONTEXT.preHeader.timestamp + val v3 = SELF.getReg(7).get + val v4 = SELF.tokens + val v5 = v4.size + val v6 = v5 == 1 + val v7 = { + (v7: Box) => + if (v6) v7.value else v7.tokens(1)._2 + } + + val v8 = v7(SELF) + val v9 = SELF.getReg(6).get + val v10 = SELF.getReg(8).get + val v11 = Coll[Coll[Byte]]() + val v12 = OUTPUTS(1) + val v13 = SELF.getReg(5).get + val v14 = SELF.getReg(4).get + val v15 = CONTEXT.dataInputs(0) + val v16 = v15.getReg(8).get + sigmaProp(v1.value >= SELF.value && v2 < v3 && v1.tokens(0) == v4(0) && { + val v17 = v7(v1) + v17 >= v8 + v9 || v10 != -1 && v17 >= v10 + } + && v1.propBytes == SELF.propBytes && v5 == v1.tokens.size && { + (v17: Box) => + if (v6) v11 else v17.tokens(1)._1 + } + (SELF) == { + (v17: Box) => + if (v6) v11 else v17.tokens(1)._1 + } + (v1) && v12.propBytes == v13 && v7(v12) >= v8 && v1.getReg(4).get == v14 && v1.getReg(5).get.size > 0 && v1.getReg(6).get == v9 && v1.getReg(7).get == if (v3 - v2 <= v16(0)) v3 + v16(1) else v3 && v1.getReg(8).get == v10 && v1.getReg(9) == SELF.getReg(9) || if (OUTPUTS.size == 5) { + val v17 = OUTPUTS(2) + val v18 = v8 / upcast(v15.getReg(4).get) + val v19 = v4(0) + val v20 = v8 / upcast(v15.getReg(6).get) + val v21 = OUTPUTS(3) + val v22 = v21.getReg(4).get + v2 >= v3 || v8 >= v10 && v10 != -1 && v7(v17) >= v18 && v17.propBytes == v15.getReg(5).get && v1.tokens(0) == v19 && v1.propBytes == v13 && v7(v12) >= v8 - v18 - v20 - if (v6) v15.getReg(7).get * 2 else 0 && v12.propBytes == v14 && blake2b256(v22.bytes) == v19._1 && v7(v21) >= v20 && v21.propBytes == v22.propBytes + } + else false) + } + "#]], + ) + } + } diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 17df1935c..fd58cda8c 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -1,5 +1,6 @@ use thiserror::Error; +use crate::mir::apply::Apply; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::bool_to_sigma::BoolToSigmaProp; @@ -11,10 +12,12 @@ use crate::mir::coll_filter::Filter; use crate::mir::coll_fold::Fold; use crate::mir::coll_map::Map; use crate::mir::coll_size::SizeOf; +use crate::mir::collection::Collection; use crate::mir::constant::Constant; use crate::mir::create_provedlog::CreateProveDlog; use crate::mir::expr::Expr; use crate::mir::extract_amount::ExtractAmount; +use crate::mir::extract_bytes::ExtractBytes; use crate::mir::extract_creation_info::ExtractCreationInfo; use crate::mir::extract_id::ExtractId; use crate::mir::extract_reg_as::ExtractRegisterAs; @@ -74,7 +77,7 @@ impl Print for Expr { Expr::ByteArrayToLong(_) => todo!(), Expr::ByteArrayToBigInt(_) => todo!(), Expr::LongToByteArray(_) => todo!(), - Expr::Collection(_) => todo!(), + Expr::Collection(v) => v.print(w), Expr::Tuple(v) => v.print(w), Expr::CalcBlake2b256(v) => v.print(w), Expr::CalcSha256(_) => todo!(), @@ -84,7 +87,7 @@ impl Print for Expr { } Expr::Global => todo!(), Expr::FuncValue(v) => v.print(w), - Expr::Apply(_) => todo!(), + Expr::Apply(v) => v.print(w), Expr::MethodCall(v) => v.expr().print(w), Expr::PropertyCall(v) => v.expr().print(w), Expr::If(v) => v.print(w), @@ -100,7 +103,7 @@ impl Print for Expr { Expr::OptionGetOrElse(_) => todo!(), Expr::ExtractAmount(v) => v.print(w), Expr::ExtractRegisterAs(v) => v.expr().print(w), - Expr::ExtractBytes(_) => todo!(), + Expr::ExtractBytes(v) => v.print(w), Expr::ExtractBytesWithNoRef(_) => todo!(), Expr::ExtractScriptBytes(v) => v.print(w), Expr::ExtractCreationInfo(v) => v.print(w), @@ -664,3 +667,56 @@ impl Print for ExtractId { .into()) } } + +impl Print for Apply { + fn print(&self, w: &mut dyn Printer) -> Result { + let func = self.func.print(w)?; + write!(w, "(")?; + let args = self + .args + .iter() + .map(|a| -> Result { a.print(w) }) + .collect::, _>>()?; + write!(w, ")")?; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Apply::new(func, args).unwrap().into()) + } +} + +impl Print for Collection { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "Coll[{}](", self.tpe())?; + match self { + Collection::BoolConstants(bools) => { + for b in bools { + write!(w, "{}, ", b)?; + } + write!(w, ")")?; + Ok(Collection::from_bools(bools.clone()).into()) + } + Collection::Exprs { elem_tpe, items } => { + let items = items + .iter() + .map(|i| { + write!(w, ", ")?; + i.print(w) + }) + .collect::, _>>()?; + write!(w, ")")?; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Collection::new(elem_tpe.clone(), items).unwrap().into()) + } + } + } +} + +impl Print for ExtractBytes { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".bytes")?; + Ok(ExtractBytes { + input: Box::new(input), + } + .into()) + } +} \ No newline at end of file From d1b0e563e15af31da96246579f3454cf8c334aa8 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 13 Sep 2023 15:15:50 +0300 Subject: [PATCH 66/74] add doc comment; --- ergotree-ir/src/mir/collection.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ergotree-ir/src/mir/collection.rs b/ergotree-ir/src/mir/collection.rs index b314243af..574a082bd 100644 --- a/ergotree-ir/src/mir/collection.rs +++ b/ergotree-ir/src/mir/collection.rs @@ -51,6 +51,7 @@ impl Collection { } } + /// Create a collection from a vector of booleans pub fn from_bools(bools: Vec) -> Self { Collection::BoolConstants(bools) } From 0eefaef2a656769f3243768b81fb3b1f56eac2ce Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 14 Sep 2023 17:09:30 +0300 Subject: [PATCH 67/74] pretty printer for ByteArrayTo* IR nodes; --- ergotree-ir/src/pretty_printer/print.rs | 30 +++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index fd58cda8c..99994369d 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -4,6 +4,8 @@ use crate::mir::apply::Apply; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::bool_to_sigma::BoolToSigmaProp; +use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; +use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::calc_blake2b256::CalcBlake2b256; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; @@ -74,8 +76,8 @@ impl Print for Expr { Expr::ByIndex(v) => v.expr().print(w), Expr::ConstPlaceholder(_) => Ok(self.clone()), Expr::SubstConstants(_) => todo!(), - Expr::ByteArrayToLong(_) => todo!(), - Expr::ByteArrayToBigInt(_) => todo!(), + Expr::ByteArrayToLong(v) => v.expr().print(w), + Expr::ByteArrayToBigInt(v) => v.expr().print(w), Expr::LongToByteArray(_) => todo!(), Expr::Collection(v) => v.print(w), Expr::Tuple(v) => v.print(w), @@ -719,4 +721,28 @@ impl Print for ExtractBytes { } .into()) } +} + +impl Print for ByteArrayToLong { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "byteArrayToLong(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(ByteArrayToLong { + input: Box::new(input), + } + .into()) + } +} + +impl Print for ByteArrayToBigInt { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "byteArrayToBigInt(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(ByteArrayToBigInt { + input: Box::new(input), + } + .into()) + } } \ No newline at end of file From 7c99195a943eaac28360ca631b26d11763da1d66 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 19 Sep 2023 17:36:40 +0300 Subject: [PATCH 68/74] impl Print for LongToByteArray and CalcSha256; --- ergotree-ir/src/pretty_printer/print.rs | 30 +++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 99994369d..bae1ace41 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -7,6 +7,7 @@ use crate::mir::bool_to_sigma::BoolToSigmaProp; use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; use crate::mir::byte_array_to_long::ByteArrayToLong; use crate::mir::calc_blake2b256::CalcBlake2b256; +use crate::mir::calc_sha256::CalcSha256; use crate::mir::coll_append::Append; use crate::mir::coll_by_index::ByIndex; use crate::mir::coll_exists::Exists; @@ -29,6 +30,7 @@ use crate::mir::get_var::GetVar; use crate::mir::global_vars::GlobalVars; use crate::mir::if_op::If; use crate::mir::logical_not::LogicalNot; +use crate::mir::long_to_byte_array::LongToByteArray; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; @@ -78,11 +80,11 @@ impl Print for Expr { Expr::SubstConstants(_) => todo!(), Expr::ByteArrayToLong(v) => v.expr().print(w), Expr::ByteArrayToBigInt(v) => v.expr().print(w), - Expr::LongToByteArray(_) => todo!(), + Expr::LongToByteArray(v) => v.print(w), Expr::Collection(v) => v.print(w), Expr::Tuple(v) => v.print(w), Expr::CalcBlake2b256(v) => v.print(w), - Expr::CalcSha256(_) => todo!(), + Expr::CalcSha256(v) => v.print(w), Expr::Context => { write!(w, "CONTEXT")?; Ok(self.clone()) @@ -745,4 +747,28 @@ impl Print for ByteArrayToBigInt { } .into()) } +} + +impl Print for LongToByteArray { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "longToByteArray(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(LongToByteArray { + input: Box::new(input), + } + .into()) + } +} + +impl Print for CalcSha256 { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "sha256(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(CalcSha256 { + input: Box::new(input), + } + .into()) + } } \ No newline at end of file From 1f7a24666d60b0ac75195cc0cbc5bfb1f0456180 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 20 Sep 2023 13:08:06 +0300 Subject: [PATCH 69/74] implmennt pretty printing for And, Or, LogicalNot, Xor, SubstConstants, Atleast; --- ergotree-ir/src/mir/expr.rs | 12 +-- ergotree-ir/src/pretty_printer/print.rs | 107 ++++++++++++++++++++++-- ergotree-ir/src/source_span.rs | 6 ++ 3 files changed, 111 insertions(+), 14 deletions(-) diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index 226aae903..bf11c30e9 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -134,15 +134,15 @@ pub enum Expr { /// Binary operation BinOp(Spanned), /// Logical AND - And(And), + And(Spanned), /// Logical OR - Or(Or), + Or(Spanned), /// Byte-wise XOR Xor(Xor), /// THRESHOLD composition for sigma expressions Atleast(Atleast), /// LogicalNot - LogicalNot(LogicalNot), + LogicalNot(Spanned), /// Negation on numeric type Negation(Spanned), /// Bit inversion on numeric type @@ -256,11 +256,11 @@ impl Expr { Expr::Fold(v) => v.expr().tpe(), Expr::SelectField(v) => v.expr().tpe(), Expr::ExtractAmount(v) => v.tpe(), - Expr::And(v) => v.tpe(), - Expr::Or(v) => v.tpe(), + Expr::And(v) => v.expr().tpe(), + Expr::Or(v) => v.expr().tpe(), Expr::Xor(v) => v.tpe(), Expr::Atleast(v) => v.tpe(), - Expr::LogicalNot(v) => v.tpe(), + Expr::LogicalNot(v) => v.expr().tpe(), Expr::Map(v) => v.expr().tpe(), Expr::Filter(v) => v.expr().tpe(), Expr::BoolToSigmaProp(v) => v.tpe(), diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index bae1ace41..6f2c1888e 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -1,6 +1,8 @@ use thiserror::Error; +use crate::mir::and::And; use crate::mir::apply::Apply; +use crate::mir::atleast::Atleast; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::bool_to_sigma::BoolToSigmaProp; @@ -35,15 +37,18 @@ use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; use crate::mir::option_is_defined::OptionIsDefined; +use crate::mir::or::Or; use crate::mir::property_call::PropertyCall; use crate::mir::select_field::SelectField; use crate::mir::sigma_and::SigmaAnd; use crate::mir::sigma_or::SigmaOr; +use crate::mir::subst_const::SubstConstants; use crate::mir::tuple::Tuple; use crate::mir::unary_op::OneArgOpTryBuild; use crate::mir::upcast::Upcast; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; +use crate::mir::xor::Xor; use crate::source_span::SourceSpan; use crate::source_span::Spanned; use crate::types::stype::SType; @@ -77,7 +82,7 @@ impl Print for Expr { Expr::GlobalVars(v) => v.print(w), Expr::ByIndex(v) => v.expr().print(w), Expr::ConstPlaceholder(_) => Ok(self.clone()), - Expr::SubstConstants(_) => todo!(), + Expr::SubstConstants(v) => v.expr().print(w), Expr::ByteArrayToLong(v) => v.expr().print(w), Expr::ByteArrayToBigInt(v) => v.expr().print(w), Expr::LongToByteArray(v) => v.print(w), @@ -89,17 +94,20 @@ impl Print for Expr { write!(w, "CONTEXT")?; Ok(self.clone()) } - Expr::Global => todo!(), + Expr::Global => { + write!(w, "GLOBAL")?; + Ok(self.clone()) + } Expr::FuncValue(v) => v.print(w), Expr::Apply(v) => v.print(w), Expr::MethodCall(v) => v.expr().print(w), Expr::PropertyCall(v) => v.expr().print(w), Expr::If(v) => v.print(w), - Expr::And(_) => todo!(), - Expr::Or(_) => todo!(), - Expr::Xor(_) => todo!(), - Expr::Atleast(_) => todo!(), - Expr::LogicalNot(v) => v.print(w), + Expr::And(v) => v.expr().print(w), + Expr::Or(v) => v.expr().print(w), + Expr::Xor(v) => v.print(w), + Expr::Atleast(v) => v.print(w), + Expr::LogicalNot(v) => v.expr().print(w), Expr::Negation(v) => v.expr().print(w), Expr::BitInversion(_) => todo!(), Expr::OptionGet(v) => v.expr().print(w), @@ -564,6 +572,38 @@ impl Print for SigmaOr { } } +impl Print for And { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + write!(w, "&&")?; + let input = self.input.print(w)?; + let length = w.current_pos() - offset; + Ok(Spanned { + expr: And { + input: Box::new(input), + }, + source_span: SourceSpan { offset, length }, + } + .into()) + } +} + +impl Print for Or { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + write!(w, "||")?; + let input = self.input.print(w)?; + let length = w.current_pos() - offset; + Ok(Spanned { + expr: Or { + input: Box::new(input), + }, + source_span: SourceSpan { offset, length }, + } + .into()) + } +} + impl Print for CreateProveDlog { fn print(&self, w: &mut dyn Printer) -> Result { write!(w, "proveDlog(")?; @@ -771,4 +811,55 @@ impl Print for CalcSha256 { } .into()) } -} \ No newline at end of file +} + +impl Print for Xor { + fn print(&self, w: &mut dyn Printer) -> Result { + let left = self.left.print(w)?; + write!(w, "^")?; + let right = self.right.print(w)?; + Ok(Xor { + left: left.into(), + right: right.into(), + } + .into()) + } +} + +impl Print for Atleast { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, ".atLeast(")?; + let bound = self.bound.print(w)?; + write!(w, ", ")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(Atleast { + input: Box::new(input), + bound: Box::new(bound), + } + .into()) + } +} + +impl Print for SubstConstants { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + write!(w, ".substConstants(")?; + let script_bytes = self.script_bytes.print(w)?; + write!(w, ", ")?; + let positions = self.positions.print(w)?; + write!(w, ", ")?; + let new_values = self.new_values.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + Ok(Spanned { + expr: SubstConstants { + script_bytes: script_bytes.into(), + positions: positions.into(), + new_values: new_values.into(), + }, + source_span: SourceSpan { offset, length }, + } + .into()) + } +} diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index acd098291..ffd9f9b02 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,5 +1,8 @@ //! Source position for an IR node in the source code +use crate::mir::logical_not::LogicalNot; +use crate::mir::or::Or; +use crate::mir::and::And; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; @@ -117,6 +120,9 @@ into_expr!(GetVar); into_expr!(DeserializeRegister); into_expr!(DeserializeContext); into_expr!(TreeLookup); +into_expr!(And); +into_expr!(Or); +into_expr!(LogicalNot); impl From for Spanned { fn from(v: T) -> Self { From b04986416137fc7e3dc8fdb6e3ce325f13fe2c05 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 22 Sep 2023 13:23:37 +0300 Subject: [PATCH 70/74] fix build after rebase; --- ergotree-interpreter/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/ergotree-interpreter/Cargo.toml b/ergotree-interpreter/Cargo.toml index 9ed5d5336..8009b1ee3 100644 --- a/ergotree-interpreter/Cargo.toml +++ b/ergotree-interpreter/Cargo.toml @@ -36,6 +36,7 @@ serde_with = { workspace = true, optional = true } proptest = { workspace = true, optional = true } scorex_crypto_avltree = "0.1.0" gf2_192 = { version = "^0.24.1", path = "../gf2_192" } +miette = { workspace = true } [features] default = ["json"] From 0bd29adc7322d918919201f1e8eec9159e83ed59 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 22 Sep 2023 15:46:31 +0300 Subject: [PATCH 71/74] implement pretty printing for BitInversion, OptionGetOrElse, Slice, ForAll, Downcast, DHT, SigmaPropBytes; --- ergotree-ir/src/pretty_printer/print.rs | 148 ++++++++++++++++++++++-- ergotree-ir/src/source_span.rs | 4 +- 2 files changed, 142 insertions(+), 10 deletions(-) diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 6f2c1888e..20fd4e335 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -4,6 +4,7 @@ use crate::mir::and::And; use crate::mir::apply::Apply; use crate::mir::atleast::Atleast; use crate::mir::bin_op::BinOp; +use crate::mir::bit_inversion::BitInversion; use crate::mir::block::BlockValue; use crate::mir::bool_to_sigma::BoolToSigmaProp; use crate::mir::byte_array_to_bigint::ByteArrayToBigInt; @@ -15,14 +16,19 @@ use crate::mir::coll_by_index::ByIndex; use crate::mir::coll_exists::Exists; use crate::mir::coll_filter::Filter; use crate::mir::coll_fold::Fold; +use crate::mir::coll_forall::ForAll; use crate::mir::coll_map::Map; use crate::mir::coll_size::SizeOf; +use crate::mir::coll_slice::Slice; use crate::mir::collection::Collection; use crate::mir::constant::Constant; +use crate::mir::create_prove_dh_tuple::CreateProveDhTuple; use crate::mir::create_provedlog::CreateProveDlog; +use crate::mir::downcast::Downcast; use crate::mir::expr::Expr; use crate::mir::extract_amount::ExtractAmount; use crate::mir::extract_bytes::ExtractBytes; +use crate::mir::extract_bytes_with_no_ref::ExtractBytesWithNoRef; use crate::mir::extract_creation_info::ExtractCreationInfo; use crate::mir::extract_id::ExtractId; use crate::mir::extract_reg_as::ExtractRegisterAs; @@ -36,12 +42,14 @@ use crate::mir::long_to_byte_array::LongToByteArray; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; +use crate::mir::option_get_or_else::OptionGetOrElse; use crate::mir::option_is_defined::OptionIsDefined; use crate::mir::or::Or; use crate::mir::property_call::PropertyCall; use crate::mir::select_field::SelectField; use crate::mir::sigma_and::SigmaAnd; use crate::mir::sigma_or::SigmaOr; +use crate::mir::sigma_prop_bytes::SigmaPropBytes; use crate::mir::subst_const::SubstConstants; use crate::mir::tuple::Tuple; use crate::mir::unary_op::OneArgOpTryBuild; @@ -109,31 +117,31 @@ impl Print for Expr { Expr::Atleast(v) => v.print(w), Expr::LogicalNot(v) => v.expr().print(w), Expr::Negation(v) => v.expr().print(w), - Expr::BitInversion(_) => todo!(), + Expr::BitInversion(v) => v.print(w), Expr::OptionGet(v) => v.expr().print(w), Expr::OptionIsDefined(v) => v.expr().print(w), - Expr::OptionGetOrElse(_) => todo!(), + Expr::OptionGetOrElse(v) => v.expr().print(w), Expr::ExtractAmount(v) => v.print(w), Expr::ExtractRegisterAs(v) => v.expr().print(w), Expr::ExtractBytes(v) => v.print(w), - Expr::ExtractBytesWithNoRef(_) => todo!(), + Expr::ExtractBytesWithNoRef(v) => v.print(w), Expr::ExtractScriptBytes(v) => v.print(w), Expr::ExtractCreationInfo(v) => v.print(w), Expr::ExtractId(v) => v.print(w), Expr::SizeOf(v) => v.print(w), - Expr::Slice(_) => todo!(), + Expr::Slice(v) => v.expr().print(w), Expr::Fold(v) => v.expr().print(w), Expr::Map(v) => v.expr().print(w), Expr::Filter(v) => v.expr().print(w), Expr::Exists(v) => v.expr().print(w), - Expr::ForAll(_) => todo!(), + Expr::ForAll(v) => v.expr().print(w), Expr::SelectField(v) => v.expr().print(w), Expr::BoolToSigmaProp(v) => v.print(w), Expr::Upcast(v) => v.print(w), - Expr::Downcast(_) => todo!(), + Expr::Downcast(v) => v.print(w), Expr::CreateProveDlog(v) => v.print(w), - Expr::CreateProveDhTuple(_) => todo!(), - Expr::SigmaPropBytes(_) => todo!(), + Expr::CreateProveDhTuple(v) => v.print(w), + Expr::SigmaPropBytes(v) => v.print(w), Expr::DecodePoint(_) => todo!(), Expr::SigmaAnd(v) => v.print(w), Expr::SigmaOr(v) => v.print(w), @@ -863,3 +871,127 @@ impl Print for SubstConstants { .into()) } } + +impl Print for BitInversion { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "~")?; + let input = self.input.print(w)?; + Ok(BitInversion { + input: Box::new(input), + } + .into()) + } +} + +impl Print for OptionGetOrElse { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".getOrElse(")?; + let default = self.default.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + expr: OptionGetOrElse::new(input, default).unwrap(), + source_span: SourceSpan { offset, length }, + } + .into()) + } +} + +impl Print for ExtractBytesWithNoRef { + fn print(&self, w: &mut dyn Printer) -> Result { + let input = self.input.print(w)?; + write!(w, ".bytesWithNoRef")?; + Ok(ExtractBytesWithNoRef { + input: Box::new(input), + } + .into()) + } +} + +impl Print for Slice { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".slice(")?; + let from = self.from.print(w)?; + write!(w, ", ")?; + let until = self.until.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + Ok(Spanned { + expr: Slice { + input: Box::new(input), + from: Box::new(from), + until: Box::new(until), + }, + source_span: SourceSpan { offset, length }, + } + .into()) + } +} + +impl Print for ForAll { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + let input = self.input.print(w)?; + write!(w, ".forall(")?; + let condition = self.condition.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + #[allow(clippy::unwrap_used)] // we only added spans + Ok(Spanned { + expr: ForAll::new(input, condition).unwrap(), + source_span: SourceSpan { offset, length }, + } + .into()) + } +} + +impl Print for Downcast { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "downcast(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(Downcast { + input: Box::new(input), + tpe: self.tpe.clone(), + } + .into()) + } +} + +impl Print for CreateProveDhTuple { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "proveDHTuple(")?; + let g = self.g.print(w)?; + write!(w, ", ")?; + let h = self.h.print(w)?; + write!(w, ", ")?; + let u = self.u.print(w)?; + write!(w, ", ")?; + let v = self.v.print(w)?; + write!(w, ")")?; + Ok(CreateProveDhTuple { + g: Box::new(g), + h: Box::new(h), + u: Box::new(u), + v: Box::new(v), + } + .into()) + } +} + +impl Print for SigmaPropBytes { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "sigmaPropBytes(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(SigmaPropBytes { + input: Box::new(input), + } + .into()) + } +} \ No newline at end of file diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index ffd9f9b02..1365f86a2 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -1,7 +1,5 @@ //! Source position for an IR node in the source code -use crate::mir::logical_not::LogicalNot; -use crate::mir::or::Or; use crate::mir::and::And; use crate::mir::bin_op::BinOp; use crate::mir::block::BlockValue; @@ -20,11 +18,13 @@ use crate::mir::deserialize_register::DeserializeRegister; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; use crate::mir::get_var::GetVar; +use crate::mir::logical_not::LogicalNot; use crate::mir::method_call::MethodCall; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; use crate::mir::option_get_or_else::OptionGetOrElse; use crate::mir::option_is_defined::OptionIsDefined; +use crate::mir::or::Or; use crate::mir::property_call::PropertyCall; use crate::mir::select_field::SelectField; use crate::mir::subst_const::SubstConstants; From b6e60840d6c1f3c1cfbf6187117a4a8bfccbdf6d Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 26 Sep 2023 15:46:22 +0300 Subject: [PATCH 72/74] impl Print for DeserializeRegister and DeserializeContext --- ergotree-ir/src/chain/address.rs | 7 ++--- ergotree-ir/src/mir/expr.rs | 8 +++--- ergotree-ir/src/pretty_printer/print.rs | 37 ++++++++++++++++++++++--- ergotree-ir/src/source_span.rs | 8 ++---- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index 5a11b1fee..1b4cc4107 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -108,10 +108,8 @@ impl Address { Err(_) => Address::P2S(tree.sigma_serialize_bytes()?), }, Expr::SigmaAnd(SigmaAnd { items }) => { - if let [Expr::BoolToSigmaProp(BoolToSigmaProp { input }), Expr::DeserializeContext(Spanned { - expr: DeserializeContext { tpe, id }, - .. - })] = items.as_slice() + if let [Expr::BoolToSigmaProp(BoolToSigmaProp { input }), Expr::DeserializeContext(DeserializeContext { tpe, id })] = + items.as_slice() { if let ( Expr::BinOp(Spanned { @@ -243,7 +241,6 @@ impl Address { tpe: SType::SSigmaProp, id: 1, } - .into(), ); let sigma_prop = Expr::BoolToSigmaProp(BoolToSigmaProp { input: Box::from(hash_equals), diff --git a/ergotree-ir/src/mir/expr.rs b/ergotree-ir/src/mir/expr.rs index bf11c30e9..f508c5009 100644 --- a/ergotree-ir/src/mir/expr.rs +++ b/ergotree-ir/src/mir/expr.rs @@ -208,12 +208,12 @@ pub enum Expr { GetVar(Spanned), /// Extract register of SELF box as `Coll[Byte]`, deserialize it into Value and inline into /// the executing script. - DeserializeRegister(Spanned), + DeserializeRegister(DeserializeRegister), /// Extracts context variable as `Coll[Byte]`, deserializes it to script and then executes /// this script in the current context. The original `Coll[Byte]` of the script is /// available as `getVar[Coll[Byte]](id)` On evaluation returns the result of the /// script execution in the current context - DeserializeContext(Spanned), + DeserializeContext(DeserializeContext), /// MultiplyGroup op for GroupElement MultiplyGroup(MultiplyGroup), /// Exponentiate op for GroupElement @@ -286,8 +286,8 @@ impl Expr { Expr::DecodePoint(v) => v.tpe(), Expr::SigmaAnd(v) => v.tpe(), Expr::SigmaOr(v) => v.tpe(), - Expr::DeserializeRegister(v) => v.expr().tpe(), - Expr::DeserializeContext(v) => v.expr().tpe(), + Expr::DeserializeRegister(v) => v.tpe(), + Expr::DeserializeContext(v) => v.tpe(), Expr::GetVar(v) => v.expr().tpe(), Expr::MultiplyGroup(v) => v.tpe(), Expr::Exponentiate(v) => v.tpe(), diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index 20fd4e335..d8e15f91d 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -24,6 +24,9 @@ use crate::mir::collection::Collection; use crate::mir::constant::Constant; use crate::mir::create_prove_dh_tuple::CreateProveDhTuple; use crate::mir::create_provedlog::CreateProveDlog; +use crate::mir::decode_point::DecodePoint; +use crate::mir::deserialize_context::DeserializeContext; +use crate::mir::deserialize_register::DeserializeRegister; use crate::mir::downcast::Downcast; use crate::mir::expr::Expr; use crate::mir::extract_amount::ExtractAmount; @@ -142,12 +145,12 @@ impl Print for Expr { Expr::CreateProveDlog(v) => v.print(w), Expr::CreateProveDhTuple(v) => v.print(w), Expr::SigmaPropBytes(v) => v.print(w), - Expr::DecodePoint(_) => todo!(), + Expr::DecodePoint(v) => v.print(w), Expr::SigmaAnd(v) => v.print(w), Expr::SigmaOr(v) => v.print(w), Expr::GetVar(v) => v.expr().print(w), - Expr::DeserializeRegister(_) => todo!(), - Expr::DeserializeContext(_) => todo!(), + Expr::DeserializeRegister(v) => v.print(w), + Expr::DeserializeContext(v) => v.print(w), Expr::MultiplyGroup(_) => todo!(), Expr::Exponentiate(_) => todo!(), Expr::XorOf(_) => todo!(), @@ -994,4 +997,30 @@ impl Print for SigmaPropBytes { } .into()) } -} \ No newline at end of file +} + +impl Print for DecodePoint { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "decodePoint(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(DecodePoint { + input: Box::new(input), + } + .into()) + } +} + +impl Print for DeserializeRegister { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "deserializeRegister({})", self.reg)?; + Ok(self.clone().into()) + } +} + +impl Print for DeserializeContext { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "deserializeContext({})", self.id)?; + Ok(self.clone().into()) + } +} diff --git a/ergotree-ir/src/source_span.rs b/ergotree-ir/src/source_span.rs index 1365f86a2..a48ae4a54 100644 --- a/ergotree-ir/src/source_span.rs +++ b/ergotree-ir/src/source_span.rs @@ -13,8 +13,6 @@ use crate::mir::coll_fold::Fold; use crate::mir::coll_forall::ForAll; use crate::mir::coll_map::Map; use crate::mir::coll_slice::Slice; -use crate::mir::deserialize_context::DeserializeContext; -use crate::mir::deserialize_register::DeserializeRegister; use crate::mir::expr::Expr; use crate::mir::extract_reg_as::ExtractRegisterAs; use crate::mir::get_var::GetVar; @@ -117,8 +115,6 @@ into_expr!(Exists); into_expr!(ForAll); into_expr!(SelectField); into_expr!(GetVar); -into_expr!(DeserializeRegister); -into_expr!(DeserializeContext); into_expr!(TreeLookup); into_expr!(And); into_expr!(Or); @@ -196,8 +192,8 @@ impl Expr { Expr::SigmaAnd(_) => SourceSpan::empty(), Expr::SigmaOr(_) => SourceSpan::empty(), Expr::GetVar(op) => op.source_span, - Expr::DeserializeRegister(op) => op.source_span, - Expr::DeserializeContext(op) => op.source_span, + Expr::DeserializeRegister(_) => SourceSpan::empty(), + Expr::DeserializeContext(_) => SourceSpan::empty(), Expr::MultiplyGroup(_) => SourceSpan::empty(), Expr::Exponentiate(_) => SourceSpan::empty(), Expr::XorOf(_) => SourceSpan::empty(), From ee9b1594564ffc8932598830dd672357632ea4c1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 27 Sep 2023 12:43:17 +0300 Subject: [PATCH 73/74] code formatting --- ergotree-ir/src/chain/address.rs | 10 ++++------ ergotree-ir/src/pretty_printer.rs | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ergotree-ir/src/chain/address.rs b/ergotree-ir/src/chain/address.rs index 1b4cc4107..43e2b9b5f 100644 --- a/ergotree-ir/src/chain/address.rs +++ b/ergotree-ir/src/chain/address.rs @@ -236,12 +236,10 @@ impl Address { } .into(), ); - let script_is_correct = Expr::DeserializeContext( - DeserializeContext { - tpe: SType::SSigmaProp, - id: 1, - } - ); + let script_is_correct = Expr::DeserializeContext(DeserializeContext { + tpe: SType::SSigmaProp, + id: 1, + }); let sigma_prop = Expr::BoolToSigmaProp(BoolToSigmaProp { input: Box::from(hash_equals), }); diff --git a/ergotree-ir/src/pretty_printer.rs b/ergotree-ir/src/pretty_printer.rs index dbada114a..234eb8358 100644 --- a/ergotree-ir/src/pretty_printer.rs +++ b/ergotree-ir/src/pretty_printer.rs @@ -625,7 +625,7 @@ mod tests { ) } -#[test] + #[test] fn amm_conc_pool() { // from eip-14 https://github.com/ergoplatform/eips/pull/27/files let p2s_addr_str = "AhCu1UkNT4c9q3B2Lb7gNgvZWCdXL8iYgmNxTYiy4S3wgKWFFW6kz9v7pvY8NqC7g4wgXXwzJY1fQVn2xrLkiyiQWsorq5dR7d5KnDAY43H4GvSVjaDciadXCSHCb8jgk8mFSQCwoZHweLmMJ25312wT85AySJgYUuzdUxMz4EnQpiwZR2XVZq3M81gycuqP9gUryryjN4J1cAF3yL3kZR3rREubBvJ2CY5hF74Xaj2jwajivkESkqq22ieWWG2sK7dk1A7KHr1MmiXGcUBAMMGPAu3mVCeFW9SongxP9hodnJThLknjWRBBBC6wq5jNkSdHrMbdaQM3XesXqGTk9KwWpnSL92E96muU2k8FQbo5isps1r5ciYVrFptfEAC3tWbwcVmRKtrgxtCex6bP5aBZYjaH6L9QQbkYriDAcQ1iZcpf3hHCqURjRXL7i72C3aGBwzzspQvhLof6x4f4gPxTCtF1bNUxddUL6DJ1PbQWzVH8taivjhHohis6sRn3Akvv4xaZRJdKZ8rDuiounRKNXi8VoNgVEZbSFYtfweRSdsiXJCkhtehLWdtFTk1eg7djASdBGKaguvtEBcGaAALVDUoH479VskPUQ6hrfS7KcWrATBdb8sf4W5MFpx7UNitzq2fzSKC96mQRUzy5uELe7Y7vexm5ArNEyr6ARkypZypSzJ2CEifjVxxRBEWVtbdqHrwP4gWv6cMdbqFWwuXAw2BZQnWpZFtKAGQ9m"; @@ -673,7 +673,7 @@ mod tests { ) } -#[test] + #[test] fn eip_22_auction() { // from https://github.com/ergoplatform/eips/blob/adbe21512cadf51a2d9af8406cfd418f95335899/eip-0022.md let p2s_addr_str = "GE68RH3VEgW6b4kN3GhYigrLxoXr9jMgMpmm3KnXJaYq1PzHieYhz7Uka86idxvBWLRLmpiA3HrxHPsX1jzQZEv5yaRDueiJqks1keM7iB1eYWMEVRUUq1MLFzdA1FHQwCfSakM3Uc8uBPqk2icxhoXvw1CVbUVtFCzcPrZzf8Jjf8gS5bCFpWQscHo14HTsdBxyV3dwL6wKu8LP8FuWJE7qCEgX9ToEiztH4ZLmFwBejnUFrCQqjLVLWpdgdnAXVyewiX9DxXKJKL4wNqhPUrYjmHEVvpZAezXjzfVMr7gKupTqAgx2AJYGh4winEDeYq9MVshX8xjJweGhbAm2RXN1euQpoepFaKqfrT2mQBTmr6edbbzYg6VJ7DoSCDzmcUupFAmZMjMiaUbgtyz2VEbPEKsmAFrZ6zdB5EUxhiYZMd6KdstsJwZCgKJSSCShTgpfqNLCdpR9JbZFQpA1uhUkuLMPvGi74V5EwijTEEtjmTVcWcVhJKv4GDr1Lqe2bMPq4jfEfqvemaY8FcrCsCSi2LZoQUeJ9VrBeotGTKccq8JhwnvNGhLUUrrm32v3bhU82jbtVBVFRD3FSv5hhS6pKHtTevjwuG7JWoR3LN7279A7zQGJWmkSWDoEhHjgxseqZ2G5bLB7ZVEzKM261QhwMwmXA1eWgq8zdBH1u9kFC9bMQ812q2DPZTuhzpBWJh74UGwaEgZLhnUrDKT58cEa4R3kfWyGCMoNw78q1E3a2eKDz8Va5wnixzT2SZFHU8DfHjPSz5rm8Mr3YxgRC6GzaasPDxTrZjuMJHU2exhqsoFvur7Q"; @@ -730,5 +730,4 @@ mod tests { "#]], ) } - } From 3a62672de4a8aea65f90f4a6941e658122d2e846 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 27 Sep 2023 13:06:51 +0300 Subject: [PATCH 74/74] impl pretty printer for MultiplyGroup, Exponentiate, XorOf, TreeLookup, CreateAvlTree; --- ergotree-ir/src/pretty_printer/print.rs | 98 +++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/ergotree-ir/src/pretty_printer/print.rs b/ergotree-ir/src/pretty_printer/print.rs index d8e15f91d..870ff6c13 100644 --- a/ergotree-ir/src/pretty_printer/print.rs +++ b/ergotree-ir/src/pretty_printer/print.rs @@ -22,12 +22,14 @@ use crate::mir::coll_size::SizeOf; use crate::mir::coll_slice::Slice; use crate::mir::collection::Collection; use crate::mir::constant::Constant; +use crate::mir::create_avl_tree::CreateAvlTree; use crate::mir::create_prove_dh_tuple::CreateProveDhTuple; use crate::mir::create_provedlog::CreateProveDlog; use crate::mir::decode_point::DecodePoint; use crate::mir::deserialize_context::DeserializeContext; use crate::mir::deserialize_register::DeserializeRegister; use crate::mir::downcast::Downcast; +use crate::mir::exponentiate::Exponentiate; use crate::mir::expr::Expr; use crate::mir::extract_amount::ExtractAmount; use crate::mir::extract_bytes::ExtractBytes; @@ -43,6 +45,7 @@ use crate::mir::if_op::If; use crate::mir::logical_not::LogicalNot; use crate::mir::long_to_byte_array::LongToByteArray; use crate::mir::method_call::MethodCall; +use crate::mir::multiply_group::MultiplyGroup; use crate::mir::negation::Negation; use crate::mir::option_get::OptionGet; use crate::mir::option_get_or_else::OptionGetOrElse; @@ -54,12 +57,14 @@ use crate::mir::sigma_and::SigmaAnd; use crate::mir::sigma_or::SigmaOr; use crate::mir::sigma_prop_bytes::SigmaPropBytes; use crate::mir::subst_const::SubstConstants; +use crate::mir::tree_lookup::TreeLookup; use crate::mir::tuple::Tuple; use crate::mir::unary_op::OneArgOpTryBuild; use crate::mir::upcast::Upcast; use crate::mir::val_def::ValDef; use crate::mir::val_use::ValUse; use crate::mir::xor::Xor; +use crate::mir::xor_of::XorOf; use crate::source_span::SourceSpan; use crate::source_span::Spanned; use crate::types::stype::SType; @@ -80,7 +85,6 @@ pub trait Print { fn print(&self, w: &mut dyn Printer) -> Result; } -#[allow(clippy::todo)] impl Print for Expr { fn print(&self, w: &mut dyn Printer) -> Result { match self { @@ -151,11 +155,11 @@ impl Print for Expr { Expr::GetVar(v) => v.expr().print(w), Expr::DeserializeRegister(v) => v.print(w), Expr::DeserializeContext(v) => v.print(w), - Expr::MultiplyGroup(_) => todo!(), - Expr::Exponentiate(_) => todo!(), - Expr::XorOf(_) => todo!(), - Expr::TreeLookup(_) => todo!(), - Expr::CreateAvlTree(_) => todo!(), + Expr::MultiplyGroup(v) => v.print(w), + Expr::Exponentiate(v) => v.print(w), + Expr::XorOf(v) => v.print(w), + Expr::TreeLookup(v) => v.expr().print(w), + Expr::CreateAvlTree(v) => v.print(w), } } } @@ -1024,3 +1028,85 @@ impl Print for DeserializeContext { Ok(self.clone().into()) } } + +impl Print for MultiplyGroup { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "multiplyGroup(")?; + let left = self.left.print(w)?; + write!(w, ", ")?; + let right = self.right.print(w)?; + write!(w, ")")?; + Ok(MultiplyGroup { + left: left.into(), + right: right.into(), + } + .into()) + } +} + +impl Print for Exponentiate { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "exponentiate(")?; + let left = self.left.print(w)?; + write!(w, ", ")?; + let right = self.right.print(w)?; + write!(w, ")")?; + Ok(Exponentiate { + left: left.into(), + right: right.into(), + } + .into()) + } +} + +impl Print for XorOf { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "xorOf(")?; + let input = self.input.print(w)?; + write!(w, ")")?; + Ok(XorOf { + input: Box::new(input), + } + .into()) + } +} + +impl Print for TreeLookup { + fn print(&self, w: &mut dyn Printer) -> Result { + let offset = w.current_pos(); + write!(w, "treeLookup(")?; + let tree = self.tree.print(w)?; + write!(w, ", ")?; + let key = self.key.print(w)?; + write!(w, ", ")?; + let proof = self.proof.print(w)?; + write!(w, ")")?; + let length = w.current_pos() - offset; + Ok(Spanned { + expr: TreeLookup { + tree: Box::new(tree), + key: Box::new(key), + proof: Box::new(proof), + }, + source_span: SourceSpan { offset, length }, + } + .into()) + } +} + +impl Print for CreateAvlTree { + fn print(&self, w: &mut dyn Printer) -> Result { + write!(w, "avlTree(")?; + let digest = self.digest.print(w)?; + write!(w, ", ")?; + let key_length = self.key_length.print(w)?; + write!(w, ")")?; + Ok(CreateAvlTree { + digest: Box::new(digest), + key_length: Box::new(key_length), + flags: self.flags.clone(), + value_length: self.value_length.clone(), + } + .into()) + } +}