1use std::convert::TryFrom;
4use std::convert::TryInto;
5
6use crate::pretty_printer::PosTrackingWriter;
7use crate::pretty_printer::Print;
8use crate::source_span::Spanned;
9use crate::types::stype::LiftIntoSType;
10use crate::types::stype::SType;
11
12use super::and::And;
13use super::apply::Apply;
14use super::bin_op::BinOp;
15use super::bit_inversion::BitInversion;
16use super::block::BlockValue;
17use super::bool_to_sigma::BoolToSigmaProp;
18use super::byte_array_to_long::ByteArrayToLong;
19use super::calc_blake2b256::CalcBlake2b256;
20use super::calc_sha256::CalcSha256;
21use super::coll_append::Append;
22use super::coll_by_index::ByIndex;
23use super::coll_exists::Exists;
24use super::coll_filter::Filter;
25use super::coll_fold::Fold;
26use super::coll_forall::ForAll;
27use super::coll_map::Map;
28use super::coll_size::SizeOf;
29use super::coll_slice::Slice;
30use super::collection::Collection;
31use super::constant::Constant;
32use super::constant::ConstantPlaceholder;
33use super::constant::Literal;
34use super::constant::TryExtractFrom;
35use super::constant::TryExtractFromError;
36use super::create_avl_tree::CreateAvlTree;
37use super::create_provedlog::CreateProveDlog;
38use super::decode_point::DecodePoint;
39use super::exponentiate::Exponentiate;
40use super::extract_amount::ExtractAmount;
41use super::extract_bytes::ExtractBytes;
42use super::extract_bytes_with_no_ref::ExtractBytesWithNoRef;
43use super::extract_creation_info::ExtractCreationInfo;
44use super::extract_id::ExtractId;
45use super::extract_reg_as::ExtractRegisterAs;
46use super::extract_script_bytes::ExtractScriptBytes;
47use super::func_value::FuncValue;
48use super::global_vars::GlobalVars;
49use super::if_op::If;
50use super::logical_not::LogicalNot;
51use super::long_to_byte_array::LongToByteArray;
52use super::method_call::MethodCall;
53use super::multiply_group::MultiplyGroup;
54use super::negation::Negation;
55use super::option_get::OptionGet;
56use super::option_get_or_else::OptionGetOrElse;
57use super::option_is_defined::OptionIsDefined;
58use super::or::Or;
59use super::property_call::PropertyCall;
60use super::select_field::SelectField;
61use super::sigma_and::SigmaAnd;
62use super::sigma_or::SigmaOr;
63use super::sigma_prop_bytes::SigmaPropBytes;
64use super::subst_const::SubstConstants;
65use super::tree_lookup::TreeLookup;
66use super::tuple::Tuple;
67use super::upcast::Upcast;
68use super::val_def::ValDef;
69use super::val_use::ValUse;
70use super::xor::Xor;
71
72extern crate derive_more;
73use crate::mir::atleast::Atleast;
74use crate::mir::byte_array_to_bigint::ByteArrayToBigInt;
75use crate::mir::create_prove_dh_tuple::CreateProveDhTuple;
76use crate::mir::deserialize_context::DeserializeContext;
77use crate::mir::deserialize_register::DeserializeRegister;
78use crate::mir::downcast::Downcast;
79use crate::mir::get_var::GetVar;
80use crate::mir::xor_of::XorOf;
81use bounded_vec::BoundedVecOutOfBounds;
82use derive_more::From;
83use derive_more::TryInto;
84use thiserror::Error;
85
86#[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
87pub enum Expr {
89 Append(Spanned<Append>),
91 Const(Constant),
93 ConstPlaceholder(ConstantPlaceholder),
95 SubstConstants(Spanned<SubstConstants>),
97 ByteArrayToLong(Spanned<ByteArrayToLong>),
99 ByteArrayToBigInt(Spanned<ByteArrayToBigInt>),
101 LongToByteArray(LongToByteArray),
103 Collection(Collection),
105 Tuple(Tuple),
107 CalcBlake2b256(CalcBlake2b256),
110 CalcSha256(CalcSha256),
112 Context,
114 Global,
116 GlobalVars(GlobalVars),
118 FuncValue(FuncValue),
120 Apply(Apply),
122 MethodCall(Spanned<MethodCall>),
124 PropertyCall(Spanned<PropertyCall>),
126 BlockValue(Spanned<BlockValue>),
128 ValDef(Spanned<ValDef>),
130 ValUse(ValUse),
132 If(If),
134 BinOp(Spanned<BinOp>),
136 And(Spanned<And>),
138 Or(Spanned<Or>),
140 Xor(Xor),
142 Atleast(Atleast),
144 LogicalNot(Spanned<LogicalNot>),
146 Negation(Spanned<Negation>),
148 BitInversion(BitInversion),
150 OptionGet(Spanned<OptionGet>),
152 OptionIsDefined(Spanned<OptionIsDefined>),
154 OptionGetOrElse(Spanned<OptionGetOrElse>),
156 ExtractAmount(ExtractAmount),
158 ExtractRegisterAs(Spanned<ExtractRegisterAs>),
160 ExtractBytes(ExtractBytes),
162 ExtractBytesWithNoRef(ExtractBytesWithNoRef),
164 ExtractScriptBytes(ExtractScriptBytes),
166 ExtractCreationInfo(ExtractCreationInfo),
169 ExtractId(ExtractId),
171 ByIndex(Spanned<ByIndex>),
173 SizeOf(SizeOf),
175 Slice(Spanned<Slice>),
177 Fold(Spanned<Fold>),
179 Map(Spanned<Map>),
181 Filter(Spanned<Filter>),
183 Exists(Spanned<Exists>),
185 ForAll(Spanned<ForAll>),
187 SelectField(Spanned<SelectField>),
189 BoolToSigmaProp(BoolToSigmaProp),
191 Upcast(Upcast),
193 Downcast(Downcast),
195 CreateProveDlog(CreateProveDlog),
197 CreateProveDhTuple(CreateProveDhTuple),
199 SigmaPropBytes(SigmaPropBytes),
201 DecodePoint(DecodePoint),
203 SigmaAnd(SigmaAnd),
205 SigmaOr(SigmaOr),
207 GetVar(Spanned<GetVar>),
209 DeserializeRegister(DeserializeRegister),
212 DeserializeContext(DeserializeContext),
217 MultiplyGroup(MultiplyGroup),
219 Exponentiate(Exponentiate),
221 XorOf(XorOf),
223 TreeLookup(Spanned<TreeLookup>),
225 CreateAvlTree(CreateAvlTree),
227}
228
229impl Expr {
230 pub fn tpe(&self) -> SType {
232 match self {
233 Expr::Append(ap) => ap.expr().tpe(),
234 Expr::Const(v) => v.tpe.clone(),
235 Expr::Collection(v) => v.tpe(),
236 Expr::SubstConstants(v) => v.expr().tpe(),
237 Expr::ByteArrayToLong(v) => v.expr().tpe(),
238 Expr::ByteArrayToBigInt(v) => v.expr().tpe(),
239 Expr::LongToByteArray(v) => v.tpe(),
240 Expr::ConstPlaceholder(v) => v.tpe.clone(),
241 Expr::CalcBlake2b256(v) => v.tpe(),
242 Expr::CalcSha256(v) => v.tpe(),
243 Expr::Global => SType::SGlobal,
244 Expr::Context => SType::SContext,
245 Expr::GlobalVars(v) => v.tpe(),
246 Expr::FuncValue(v) => v.tpe(),
247 Expr::Apply(v) => v.tpe(),
248 Expr::MethodCall(v) => v.expr().tpe(),
249 Expr::PropertyCall(v) => v.expr().tpe(),
250 Expr::BlockValue(v) => v.expr().tpe(),
251 Expr::ValDef(v) => v.expr().tpe(),
252 Expr::ValUse(v) => v.tpe.clone(),
253 Expr::BinOp(v) => v.expr().tpe(),
254 Expr::OptionGet(v) => v.expr().tpe(),
255 Expr::ExtractRegisterAs(v) => v.expr().tpe(),
256 Expr::Fold(v) => v.expr().tpe(),
257 Expr::SelectField(v) => v.expr().tpe(),
258 Expr::ExtractAmount(v) => v.tpe(),
259 Expr::And(v) => v.expr().tpe(),
260 Expr::Or(v) => v.expr().tpe(),
261 Expr::Xor(v) => v.tpe(),
262 Expr::Atleast(v) => v.tpe(),
263 Expr::LogicalNot(v) => v.expr().tpe(),
264 Expr::Map(v) => v.expr().tpe(),
265 Expr::Filter(v) => v.expr().tpe(),
266 Expr::BoolToSigmaProp(v) => v.tpe(),
267 Expr::Upcast(v) => v.tpe(),
268 Expr::Downcast(v) => v.tpe(),
269 Expr::If(v) => v.tpe(),
270 Expr::ByIndex(v) => v.expr().tpe(),
271 Expr::ExtractScriptBytes(v) => v.tpe(),
272 Expr::SizeOf(v) => v.tpe(),
273 Expr::Slice(v) => v.expr().tpe(),
274 Expr::CreateProveDlog(v) => v.tpe(),
275 Expr::CreateProveDhTuple(v) => v.tpe(),
276 Expr::ExtractCreationInfo(v) => v.tpe(),
277 Expr::Exists(v) => v.expr().tpe(),
278 Expr::ExtractId(v) => v.tpe(),
279 Expr::SigmaPropBytes(v) => v.tpe(),
280 Expr::OptionIsDefined(v) => v.expr().tpe(),
281 Expr::OptionGetOrElse(v) => v.expr().tpe(),
282 Expr::Negation(v) => v.expr().tpe(),
283 Expr::BitInversion(v) => v.tpe(),
284 Expr::ForAll(v) => v.expr().tpe(),
285 Expr::Tuple(v) => v.tpe(),
286 Expr::DecodePoint(v) => v.tpe(),
287 Expr::SigmaAnd(v) => v.tpe(),
288 Expr::SigmaOr(v) => v.tpe(),
289 Expr::DeserializeRegister(v) => v.tpe(),
290 Expr::DeserializeContext(v) => v.tpe(),
291 Expr::GetVar(v) => v.expr().tpe(),
292 Expr::MultiplyGroup(v) => v.tpe(),
293 Expr::Exponentiate(v) => v.tpe(),
294 Expr::XorOf(v) => v.tpe(),
295 Expr::ExtractBytes(v) => v.tpe(),
296 Expr::ExtractBytesWithNoRef(v) => v.tpe(),
297 Expr::TreeLookup(v) => v.expr().tpe(),
298 Expr::CreateAvlTree(v) => v.tpe(),
299 }
300 }
301
302 pub fn post_eval_tpe(&self) -> SType {
304 match self.tpe() {
305 SType::SFunc(sfunc) => *sfunc.t_range,
306 tpe => tpe,
307 }
308 }
309
310 pub fn check_post_eval_tpe(
312 &self,
313 expected_tpe: &SType,
314 ) -> Result<(), InvalidExprEvalTypeError> {
315 let expr_tpe = self.post_eval_tpe();
316 if &expr_tpe == expected_tpe {
317 Ok(())
318 } else {
319 use std::backtrace::Backtrace;
320 let backtrace = Backtrace::capture();
321 Err(InvalidExprEvalTypeError(format!(
322 "expected: {0:?}, got: {1:?}\nBacktrace:\n{backtrace}",
323 expected_tpe, expr_tpe
324 )))
325 }
326 }
327
328 pub fn debug_tree(&self) -> String {
330 let tree = format!("{:#?}", self);
331 tree
332 }
333
334 pub fn to_string_pretty(&self) -> String {
336 let mut printer = PosTrackingWriter::new();
337 #[allow(clippy::unwrap_used)] let _spanned_expr = self.print(&mut printer).unwrap();
339 printer.as_string()
340 }
341}
342
343impl<T: Into<Literal> + LiftIntoSType> From<T> for Expr {
344 fn from(t: T) -> Self {
345 Expr::Const(Constant {
346 tpe: T::stype(),
347 v: t.into(),
348 })
349 }
350}
351
352#[derive(Error, PartialEq, Eq, Debug, Clone)]
354#[error("InvalidArgumentError: {0}")]
355pub struct InvalidArgumentError(pub String);
356
357#[derive(PartialEq, Eq, Debug, Clone, Error)]
359#[error("InvalidExprEvalTypeError: {0}")]
360pub struct InvalidExprEvalTypeError(pub String);
361
362impl From<InvalidExprEvalTypeError> for InvalidArgumentError {
363 fn from(e: InvalidExprEvalTypeError) -> Self {
364 InvalidArgumentError(format!("InvalidExprEvalTypeError: {0}", e))
365 }
366}
367
368impl From<BoundedVecOutOfBounds> for InvalidArgumentError {
369 fn from(e: BoundedVecOutOfBounds) -> Self {
370 InvalidArgumentError(format!("BoundedVecOutOfBounds: {0}", e))
371 }
372}
373
374impl<T: TryFrom<Expr>> TryExtractFrom<Expr> for T {
375 fn try_extract_from(v: Expr) -> Result<Self, TryExtractFromError> {
376 let res: Result<Self, TryExtractFromError> = v.clone().try_into().map_err(|_| {
377 TryExtractFromError(format!(
378 "Cannot extract {0:?} from {1:?}",
379 std::any::type_name::<T>(),
380 v
381 ))
382 });
383 res
384 }
385}
386
387#[cfg(feature = "arbitrary")]
388#[allow(clippy::unwrap_used)]
389#[allow(clippy::panic)]
390#[allow(clippy::todo)]
391pub(crate) mod arbitrary {
393 use super::*;
394 use crate::mir::func_value::FuncArg;
395 use crate::sigma_protocol::sigma_boolean::ProveDlog;
396 use crate::types::sfunc::SFunc;
397 use proptest::collection::*;
398 use proptest::prelude::*;
399 use std::sync::Arc;
400
401 #[derive(PartialEq, Eq, Debug, Clone)]
403 pub struct ArbExprParams {
404 pub tpe: SType,
406 pub depth: usize,
408 }
409
410 impl Default for ArbExprParams {
411 fn default() -> Self {
412 ArbExprParams {
413 tpe: SType::SBoolean,
414 depth: 1,
415 }
416 }
417 }
418
419 fn numeric_nested_expr(depth: usize, elem_tpe: &SType) -> BoxedStrategy<Expr> {
420 prop_oneof![any_with::<BinOp>(ArbExprParams {
421 tpe: elem_tpe.clone(),
422 depth
423 })
424 .prop_map_into(),]
425 .boxed()
426 }
427
428 fn bool_nested_expr(depth: usize) -> BoxedStrategy<Expr> {
429 prop_oneof![
430 any_with::<BinOp>(ArbExprParams {
431 tpe: SType::SBoolean,
432 depth
433 })
434 .prop_map_into(),
435 any_with::<And>(depth).prop_map_into(),
436 any_with::<Or>(depth).prop_map_into(),
437 any_with::<LogicalNot>(depth).prop_map_into(),
438 ]
439 .boxed()
440 }
441
442 fn coll_nested_numeric(depth: usize, elem_tpe: &SType) -> BoxedStrategy<Expr> {
443 let ty = elem_tpe.clone();
444 vec(numeric_nested_expr(depth, elem_tpe), 0..10)
445 .prop_map(move |items| Collection::new(ty.clone(), items).unwrap())
446 .prop_map_into()
447 .boxed()
448 }
449
450 fn sigma_prop_nested_expr(_depth: usize) -> BoxedStrategy<Expr> {
451 prop_oneof![
452 any::<ProveDlog>().prop_map(|pk| Expr::Const(pk.into())),
453 any::<SigmaAnd>().prop_map_into(),
454 any::<SigmaOr>().prop_map_into(),
455 ]
456 .boxed()
457 }
458
459 fn coll_nested_expr(depth: usize, elem_tpe: &SType) -> BoxedStrategy<Expr> {
460 match elem_tpe {
461 SType::SBoolean => vec(bool_nested_expr(depth), 0..10)
462 .prop_map(|items| Collection::new(SType::SBoolean, items).unwrap())
463 .prop_map_into()
464 .boxed(),
465 SType::SByte => coll_nested_numeric(depth, elem_tpe),
466 SType::SShort => coll_nested_numeric(depth, elem_tpe),
467 SType::SInt => coll_nested_numeric(depth, elem_tpe),
468 SType::SLong => coll_nested_numeric(depth, elem_tpe),
469 SType::SBigInt => coll_nested_numeric(depth, elem_tpe),
470
471 SType::STypeVar(_) => prop_oneof![
472 vec(bool_nested_expr(depth), 0..10).prop_map(|items| Collection::new(
473 SType::SBoolean,
474 items
475 )
476 .unwrap()),
477 vec(numeric_nested_expr(depth, &SType::SInt), 0..10)
478 .prop_map(|items| Collection::new(SType::SInt, items).unwrap())
479 ]
480 .prop_map_into()
481 .boxed(),
482 SType::SSigmaProp => vec(sigma_prop_nested_expr(depth), 0..10)
483 .prop_map(|items| Collection::new(SType::SSigmaProp, items).unwrap())
484 .prop_map_into()
485 .boxed(),
486
487 _ => panic!("Nested expression not implemented for {:?}", &elem_tpe),
488 }
489 }
490
491 fn any_nested_expr(depth: usize) -> BoxedStrategy<Expr> {
492 prop_oneof![
493 bool_nested_expr(depth),
494 numeric_nested_expr(depth, &SType::SByte),
495 numeric_nested_expr(depth, &SType::SShort),
496 numeric_nested_expr(depth, &SType::SInt),
497 numeric_nested_expr(depth, &SType::SLong),
498 numeric_nested_expr(depth, &SType::SBigInt),
499 ]
500 .boxed()
501 }
502
503 fn nested_expr(tpe: SType, depth: usize) -> BoxedStrategy<Expr> {
504 match tpe {
505 SType::SAny => any_nested_expr(depth),
506 SType::SBoolean => bool_nested_expr(depth),
507 SType::SByte => numeric_nested_expr(depth, &tpe),
508 SType::SShort => numeric_nested_expr(depth, &tpe),
509 SType::SInt => numeric_nested_expr(depth, &tpe),
510 SType::SLong => numeric_nested_expr(depth, &tpe),
511 SType::SBigInt => numeric_nested_expr(depth, &tpe),
512 SType::SColl(elem_type) => coll_nested_expr(depth, elem_type.as_ref()),
513 SType::SSigmaProp => sigma_prop_nested_expr(depth),
514 _ => todo!("nested expr is not implemented for type: {:?}", tpe),
515 }
516 .boxed()
517 }
518
519 fn int_non_nested_expr() -> BoxedStrategy<Expr> {
520 prop_oneof![Just(GlobalVars::Height.into()),].boxed()
521 }
522
523 fn constant(tpe: &SType) -> BoxedStrategy<Expr> {
524 any_with::<Constant>(tpe.clone().into())
525 .prop_map_into()
526 .boxed()
527 }
528
529 fn bool_non_nested_expr() -> BoxedStrategy<Expr> {
530 prop_oneof![any_with::<Constant>(SType::SBoolean.into()).prop_map_into()].boxed()
531 }
532
533 fn any_non_nested_expr() -> BoxedStrategy<Expr> {
534 prop_oneof![int_non_nested_expr(), bool_non_nested_expr()].boxed()
535 }
536
537 fn coll_non_nested_expr(elem_tpe: &SType) -> BoxedStrategy<Expr> {
538 match elem_tpe {
539 SType::SBoolean => any_with::<Constant>(SType::SColl(Arc::new(SType::SBoolean)).into())
540 .prop_map(Expr::Const)
541 .boxed(),
542 SType::SByte => any_with::<Constant>(SType::SColl(Arc::new(SType::SByte)).into())
543 .prop_map(Expr::Const)
544 .boxed(),
545 SType::SShort => any_with::<Constant>(SType::SColl(Arc::new(SType::SShort)).into())
546 .prop_map(Expr::Const)
547 .boxed(),
548 SType::SInt => any_with::<Constant>(SType::SColl(Arc::new(SType::SInt)).into())
549 .prop_map(Expr::Const)
550 .boxed(),
551 SType::SLong => any_with::<Constant>(SType::SColl(Arc::new(SType::SLong)).into())
552 .prop_map(Expr::Const)
553 .boxed(),
554 _ => todo!("Collection of {0:?} is not yet implemented", elem_tpe),
555 }
556 }
557
558 fn non_nested_expr(tpe: &SType) -> BoxedStrategy<Expr> {
559 match tpe {
560 SType::SAny => any_non_nested_expr(),
561 SType::SInt => int_non_nested_expr(),
562 SType::SBoolean => bool_non_nested_expr(),
563 SType::SColl(elem_type) => coll_non_nested_expr(elem_type),
564 t => constant(t),
565 }
566 }
567
568 fn sfunc_expr(sfunc: SFunc) -> BoxedStrategy<Expr> {
569 match (sfunc.t_dom.first().unwrap(), *sfunc.t_range) {
570 (SType::SBoolean, SType::SBoolean) => any_with::<Expr>(ArbExprParams {
571 tpe: SType::SBoolean,
572 depth: 2,
573 })
574 .prop_map(|expr| {
575 Expr::FuncValue(FuncValue::new(
576 vec![FuncArg {
577 idx: 1.into(),
578 tpe: SType::SBoolean,
579 }],
580 expr,
581 ))
582 })
583 .boxed(),
584 _ => todo!(),
585 }
586 }
587
588 impl Arbitrary for Expr {
589 type Parameters = ArbExprParams;
590 type Strategy = BoxedStrategy<Self>;
591
592 fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
593 if args.depth == 0 {
594 match args.tpe {
595 SType::SFunc(sfunc) => sfunc_expr(sfunc),
596 _ => prop_oneof![
597 any_with::<Constant>(args.tpe.clone().into())
598 .prop_map(Expr::Const)
599 .boxed(),
600 non_nested_expr(&args.tpe)
601 ]
602 .boxed(),
603 }
604 } else {
605 nested_expr(args.tpe, args.depth - 1)
606 }
607 }
608 }
609}
610
611#[cfg(test)]
612mod tests {}