Create new helper functions to take care of force and delaying branch terms
This commit is contained in:
parent
23a3134642
commit
d7e9fef4d3
|
@ -932,12 +932,8 @@ pub fn unknown_data_to_type(term: Term<Name>, field_type: &Type) -> Term<Name> {
|
|||
)
|
||||
.lambda("__list_data")
|
||||
.apply(Term::unlist_data().apply(term)),
|
||||
Some(UplcType::Bool) => {
|
||||
Term::unwrap_bool_or(term, |result| result.delay(), &Term::Error.delay())
|
||||
}
|
||||
Some(UplcType::Unit) => {
|
||||
Term::unwrap_void_or(term, |result| result.delay(), &Term::Error.delay())
|
||||
}
|
||||
Some(UplcType::Bool) => Term::unwrap_bool_or(term, |result| result, &Term::Error.delay()),
|
||||
Some(UplcType::Unit) => Term::unwrap_void_or(term, |result| result, &Term::Error.delay()),
|
||||
|
||||
Some(UplcType::Data) | None => term,
|
||||
}
|
||||
|
|
|
@ -5112,119 +5112,73 @@ fn expect_head3_cast_data_no_tail() {
|
|||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::var("tail_0")
|
||||
.choose_list(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("tail_1")
|
||||
.choose_list(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("tail_2")
|
||||
.choose_list(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::tail_list()
|
||||
.apply(Term::var("tail_2"))
|
||||
.choose_list(
|
||||
Term::equals_integer()
|
||||
let then = Term::equals_integer()
|
||||
.apply(Term::var("h"))
|
||||
.apply(Term::var("h"))
|
||||
.delayed_if_then_else(
|
||||
Term::equals_integer()
|
||||
.apply(Term::var("i"))
|
||||
.apply(Term::var("i")),
|
||||
Term::bool(false),
|
||||
)
|
||||
.delayed_if_then_else(
|
||||
Term::equals_integer()
|
||||
.apply(Term::var("j"))
|
||||
.apply(Term::var("j")),
|
||||
Term::bool(false),
|
||||
)
|
||||
.delay(),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
)
|
||||
.force()
|
||||
.lambda("j")
|
||||
.apply(
|
||||
Term::var("__var")
|
||||
.choose_data(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::un_i_data().apply(Term::var("__var")).delay(),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
)
|
||||
.force()
|
||||
.lambda("__var")
|
||||
.apply(Term::head_list().apply(Term::var("tail_2"))),
|
||||
)
|
||||
.delay(),
|
||||
)
|
||||
.force()
|
||||
.lambda("tail_2")
|
||||
.apply(Term::tail_list().apply(Term::var("tail_1")))
|
||||
.lambda("i")
|
||||
.apply(
|
||||
Term::var("__var")
|
||||
.choose_data(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::un_i_data().apply(Term::var("__var")).delay(),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
)
|
||||
.force()
|
||||
.lambda("__var")
|
||||
.apply(Term::head_list().apply(Term::var("tail_1"))),
|
||||
)
|
||||
.delay(),
|
||||
)
|
||||
.force()
|
||||
.lambda("tail_1")
|
||||
.apply(Term::tail_list().apply(Term::var("tail_0")))
|
||||
.lambda("h")
|
||||
.apply(
|
||||
Term::var("__var")
|
||||
.choose_data(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::un_i_data().apply(Term::var("__var")).delay(),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
)
|
||||
.force()
|
||||
.lambda("__var")
|
||||
.apply(Term::head_list().apply(Term::var("tail_0"))),
|
||||
)
|
||||
.delay(),
|
||||
)
|
||||
.force()
|
||||
.lambda("tail_0")
|
||||
.apply(
|
||||
);
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::data(Data::list(vec![
|
||||
Data::integer(1.into()),
|
||||
Data::integer(2.into()),
|
||||
Data::integer(3.into()),
|
||||
]))
|
||||
.choose_data(
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::list_values(vec![
|
||||
Constant::Data(Data::integer(1.into())),
|
||||
Constant::Data(Data::integer(2.into())),
|
||||
Constant::Data(Data::integer(3.into())),
|
||||
])
|
||||
.choose_list(
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::var("__var")
|
||||
.choose_data(
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::tail_list()
|
||||
.apply(Term::list_values(vec![
|
||||
Constant::Data(Data::integer(1.into())),
|
||||
Constant::Data(Data::integer(2.into())),
|
||||
Constant::Data(Data::integer(3.into())),
|
||||
]))
|
||||
.choose_list(
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
then.lambda("__var").apply(todo!()).delay(),
|
||||
)
|
||||
.force()
|
||||
.lambda("h")
|
||||
.apply(Term::un_i_data().apply(Term::var("__var")))
|
||||
.delay(),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h,i,j]:List<Int>=a"),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
)
|
||||
.force(),
|
||||
.force()
|
||||
.lambda("__var")
|
||||
.apply(Term::head_list().apply(Term::list_values(vec![
|
||||
Constant::Data(Data::integer(1.into())),
|
||||
Constant::Data(Data::integer(2.into())),
|
||||
Constant::Data(Data::integer(3.into())),
|
||||
])))
|
||||
.delay(),
|
||||
)
|
||||
.lambda("expect[h,i,j]:List<Int>=a")
|
||||
.force()
|
||||
.delay(),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
Term::var("expect[h]:List<Int>=a"),
|
||||
)
|
||||
.force()
|
||||
.lambda("expect[h]:List<Int>=a")
|
||||
.apply(
|
||||
Term::Error
|
||||
.delayed_trace(Term::string("expect [h, i, j]: List<Int> = a"))
|
||||
.delayed_trace(Term::string("expect [h]: List<Int> = a"))
|
||||
.delay(),
|
||||
),
|
||||
false,
|
||||
|
|
|
@ -421,6 +421,28 @@ impl<T> Term<T> {
|
|||
.force()
|
||||
}
|
||||
|
||||
/// Note the otherwise is expected to be a delayed term cast to a Var
|
||||
pub fn delay_empty_choose_list(self, empty: Self, otherwise: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::ChooseList)
|
||||
.force()
|
||||
.force()
|
||||
.apply(self)
|
||||
.apply(empty.delay())
|
||||
.apply(otherwise)
|
||||
.force()
|
||||
}
|
||||
|
||||
/// Note the otherwise is expected to be a delayed term cast to a Var
|
||||
pub fn delay_filled_choose_list(self, otherwise: Self, filled: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::ChooseList)
|
||||
.force()
|
||||
.force()
|
||||
.apply(self)
|
||||
.apply(otherwise)
|
||||
.apply(filled.delay())
|
||||
.force()
|
||||
}
|
||||
|
||||
pub fn delayed_choose_unit(self, then_term: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::ChooseUnit)
|
||||
.force()
|
||||
|
@ -438,6 +460,26 @@ impl<T> Term<T> {
|
|||
.force()
|
||||
}
|
||||
|
||||
/// Note the otherwise is expected to be a delayed term cast to a Var
|
||||
pub fn delay_true_if_then_else(self, then: Self, otherwise: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::IfThenElse)
|
||||
.force()
|
||||
.apply(self)
|
||||
.apply(then.delay())
|
||||
.apply(otherwise)
|
||||
.force()
|
||||
}
|
||||
|
||||
/// Note the otherwise is expected to be a delayed term cast to a Var
|
||||
pub fn delay_false_if_then_else(self, otherwise: Self, alternative: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::IfThenElse)
|
||||
.force()
|
||||
.apply(self)
|
||||
.apply(otherwise)
|
||||
.apply(alternative.delay())
|
||||
.force()
|
||||
}
|
||||
|
||||
pub fn delayed_trace(self, msg_term: Self) -> Self {
|
||||
Term::Builtin(DefaultFunction::Trace)
|
||||
.force()
|
||||
|
@ -596,8 +638,8 @@ impl Term<Name> {
|
|||
/// Convert an arbitrary 'term' into a bool term and pass it into a 'callback'.
|
||||
/// Continue the execution 'otherwise' with a different branch.
|
||||
///
|
||||
/// Note that the 'otherwise' term as well as the callback's result are expected
|
||||
/// to be delayed terms.
|
||||
/// Note that the 'otherwise' term is expected
|
||||
/// to be a delayed term.
|
||||
pub fn unwrap_bool_or<F>(self, callback: F, otherwise: &Term<Name>) -> Term<Name>
|
||||
where
|
||||
F: FnOnce(Term<Name>) -> Term<Name>,
|
||||
|
@ -605,11 +647,13 @@ impl Term<Name> {
|
|||
Term::unconstr_data()
|
||||
.apply(self)
|
||||
.as_var("__pair__", |pair| {
|
||||
Term::snd_pair().apply(Term::Var(pair.clone())).choose_list(
|
||||
Term::snd_pair()
|
||||
.apply(Term::Var(pair.clone()))
|
||||
.delay_empty_choose_list(
|
||||
Term::less_than_equals_integer()
|
||||
.apply(Term::integer(2.into()))
|
||||
.apply(Term::fst_pair().apply(Term::Var(pair.clone())))
|
||||
.if_then_else(
|
||||
.delay_false_if_then_else(
|
||||
otherwise.clone(),
|
||||
callback(
|
||||
Term::equals_integer()
|
||||
|
@ -620,14 +664,13 @@ impl Term<Name> {
|
|||
otherwise.clone(),
|
||||
)
|
||||
})
|
||||
.force()
|
||||
}
|
||||
|
||||
/// Convert an arbitrary 'term' into a unit term and pass it into a 'callback'.
|
||||
/// Continue the execution 'otherwise' with a different branch.
|
||||
///
|
||||
/// Note that the 'otherwise' term as well as the callback's result are expected
|
||||
/// to be delayed terms.
|
||||
/// Note that the 'otherwise' term is expected
|
||||
/// to be a delayed term.
|
||||
pub fn unwrap_void_or<F>(self, callback: F, otherwise: &Term<Name>) -> Term<Name>
|
||||
where
|
||||
F: FnOnce(Term<Name>) -> Term<Name>,
|
||||
|
@ -636,63 +679,58 @@ impl Term<Name> {
|
|||
Term::equals_integer()
|
||||
.apply(Term::integer(0.into()))
|
||||
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(self.clone())))
|
||||
.if_then_else(
|
||||
.delay_true_if_then_else(
|
||||
Term::snd_pair()
|
||||
.apply(Term::unconstr_data().apply(self))
|
||||
.choose_list(callback(Term::unit()), otherwise.clone())
|
||||
.force()
|
||||
.delay(),
|
||||
.delay_empty_choose_list(callback(Term::unit()), otherwise.clone()),
|
||||
otherwise.clone(),
|
||||
)
|
||||
.force()
|
||||
}
|
||||
|
||||
/// Convert an arbitrary 'term' into a pair and pass it into a 'callback'.
|
||||
/// Continue the execution 'otherwise' with a different branch.
|
||||
///
|
||||
/// Note that the 'otherwise' term as well as the callback's result are expected
|
||||
/// to be delayed terms.
|
||||
/// Note that the 'otherwise' term is expected
|
||||
/// to be a delayed term.
|
||||
pub fn unwrap_pair_or<F>(self, callback: F, otherwise: &Term<Name>) -> Term<Name>
|
||||
where
|
||||
F: FnOnce(Term<Name>) -> Term<Name>,
|
||||
{
|
||||
self.as_var("__list_data", |list| {
|
||||
let left = Term::head_list().apply(Term::Var(list.clone()));
|
||||
|
||||
Term::unwrap_tail_or(
|
||||
list,
|
||||
|tail| {
|
||||
tail.as_var("__tail", |tail| {
|
||||
let right = Term::head_list().apply(Term::Var(tail.clone()));
|
||||
|
||||
Term::unwrap_tail_or(
|
||||
tail,
|
||||
|leftovers| {
|
||||
leftovers
|
||||
.choose_list(
|
||||
leftovers.delay_empty_choose_list(
|
||||
callback(Term::mk_pair_data().apply(left).apply(right)),
|
||||
otherwise.clone(),
|
||||
)
|
||||
.force()
|
||||
.delay()
|
||||
},
|
||||
otherwise,
|
||||
)
|
||||
})
|
||||
.force()
|
||||
.delay()
|
||||
},
|
||||
otherwise,
|
||||
)
|
||||
.force()
|
||||
})
|
||||
.force()
|
||||
}
|
||||
|
||||
/// Continue with the tail of a list, if any; or fallback 'otherwise'.
|
||||
///
|
||||
/// Note that the 'otherwise' term is expected
|
||||
/// to be a delayed term.
|
||||
fn unwrap_tail_or<F>(var: Rc<Name>, callback: F, otherwise: &Term<Name>) -> Term<Name>
|
||||
where
|
||||
F: FnOnce(Term<Name>) -> Term<Name>,
|
||||
{
|
||||
Term::Var(var.clone()).choose_list(
|
||||
Term::Var(var.clone()).delay_filled_choose_list(
|
||||
otherwise.clone(),
|
||||
callback(Term::tail_list().apply(Term::Var(var))),
|
||||
)
|
||||
|
@ -722,7 +760,7 @@ mod tests {
|
|||
#[test]
|
||||
fn unwrap_bool_or_false() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(0, vec![])).unwrap_bool_or(|b| b.delay(), &Term::Error.delay()),
|
||||
Term::data(Data::constr(0, vec![])).unwrap_bool_or(|b| b, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(result, Ok(Term::bool(false)));
|
||||
|
@ -731,7 +769,7 @@ mod tests {
|
|||
#[test]
|
||||
fn unwrap_bool_or_true() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(1, vec![])).unwrap_bool_or(|b| b.delay(), &Term::Error.delay()),
|
||||
Term::data(Data::constr(1, vec![])).unwrap_bool_or(|b| b, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(result, Ok(Term::bool(true)));
|
||||
|
@ -741,7 +779,7 @@ mod tests {
|
|||
fn unwrap_bool_or_extra_args() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(1, vec![Data::integer(42.into())]))
|
||||
.unwrap_bool_or(|b| b.delay(), &Term::Error.delay()),
|
||||
.unwrap_bool_or(|b| b, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(result, Err(Error::EvaluationFailure));
|
||||
|
@ -750,7 +788,7 @@ mod tests {
|
|||
#[test]
|
||||
fn unwrap_bool_or_invalid_constr_hi() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(2, vec![])).unwrap_bool_or(|b| b.delay(), &Term::Error.delay()),
|
||||
Term::data(Data::constr(2, vec![])).unwrap_bool_or(|b| b, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(result, Err(Error::EvaluationFailure));
|
||||
|
@ -759,7 +797,7 @@ mod tests {
|
|||
#[test]
|
||||
fn unwrap_tail_or_0_elems() {
|
||||
let result = quick_eval(Term::list_values(vec![]).as_var("__tail", |tail| {
|
||||
Term::unwrap_tail_or(tail, |p| p.delay(), &Term::Error.delay()).force()
|
||||
Term::unwrap_tail_or(tail, |p| p, &Term::Error.delay())
|
||||
}));
|
||||
|
||||
assert_eq!(result, Err(Error::EvaluationFailure));
|
||||
|
@ -770,7 +808,7 @@ mod tests {
|
|||
let result = quick_eval(
|
||||
Term::list_values(vec![Constant::Data(Data::integer(1.into()))])
|
||||
.as_var("__tail", |tail| {
|
||||
Term::unwrap_tail_or(tail, |p| p.delay(), &Term::Error.delay()).force()
|
||||
Term::unwrap_tail_or(tail, |p| p, &Term::Error.delay())
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -785,7 +823,7 @@ mod tests {
|
|||
Constant::Data(Data::integer(2.into())),
|
||||
])
|
||||
.as_var("__tail", |tail| {
|
||||
Term::unwrap_tail_or(tail, |p| p.delay(), &Term::Error.delay()).force()
|
||||
Term::unwrap_tail_or(tail, |p| p, &Term::Error.delay())
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -804,7 +842,7 @@ mod tests {
|
|||
Constant::Data(Data::integer(14.into())),
|
||||
Constant::Data(Data::bytestring(vec![1, 2, 3])),
|
||||
])
|
||||
.unwrap_pair_or(|p| p.delay(), &Term::Error.delay()),
|
||||
.unwrap_pair_or(|p| p, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
@ -820,7 +858,7 @@ mod tests {
|
|||
fn unwrap_pair_or_not_enough_args_1() {
|
||||
let result = quick_eval(
|
||||
Term::list_values(vec![Constant::Data(Data::integer(1.into()))])
|
||||
.unwrap_pair_or(|p| p.delay(), &Term::Error.delay()),
|
||||
.unwrap_pair_or(|p| p, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(result, Err(Error::EvaluationFailure));
|
||||
|
@ -828,9 +866,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn unwrap_pair_or_not_enough_args_0() {
|
||||
let result = quick_eval(
|
||||
Term::list_values(vec![]).unwrap_pair_or(|p| p.delay(), &Term::Error.delay()),
|
||||
);
|
||||
let result =
|
||||
quick_eval(Term::list_values(vec![]).unwrap_pair_or(|p| p, &Term::Error.delay()));
|
||||
|
||||
assert_eq!(result, Err(Error::EvaluationFailure));
|
||||
}
|
||||
|
@ -843,7 +880,7 @@ mod tests {
|
|||
Constant::Data(Data::integer(2.into())),
|
||||
Constant::Data(Data::integer(3.into())),
|
||||
])
|
||||
.unwrap_pair_or(|p| p.delay(), &Term::Error.delay()),
|
||||
.unwrap_pair_or(|p| p, &Term::Error.delay()),
|
||||
);
|
||||
|
||||
assert_eq!(result, Err(Error::EvaluationFailure));
|
||||
|
@ -853,7 +890,7 @@ mod tests {
|
|||
fn unwrap_void_or_happy() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(0, vec![])).as_var("__unit", |unit| {
|
||||
Term::Var(unit).unwrap_void_or(|u| u.delay(), &Term::Error.delay())
|
||||
Term::Var(unit).unwrap_void_or(|u| u, &Term::Error.delay())
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -864,7 +901,7 @@ mod tests {
|
|||
fn unwrap_void_or_wrong_constr() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(14, vec![])).as_var("__unit", |unit| {
|
||||
Term::Var(unit).unwrap_void_or(|u| u.delay(), &Term::Error.delay())
|
||||
Term::Var(unit).unwrap_void_or(|u| u, &Term::Error.delay())
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -875,7 +912,7 @@ mod tests {
|
|||
fn unwrap_void_or_too_many_args() {
|
||||
let result = quick_eval(
|
||||
Term::data(Data::constr(0, vec![Data::integer(0.into())])).as_var("__unit", |unit| {
|
||||
Term::Var(unit).unwrap_void_or(|u| u.delay(), &Term::Error.delay())
|
||||
Term::Var(unit).unwrap_void_or(|u| u, &Term::Error.delay())
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue