Refactor unknown_data_to_type, break down into smaller functions.

This commit is contained in:
KtorZ 2024-08-01 12:29:34 +02:00 committed by Kasey
parent c3a61706b5
commit 9610237616
2 changed files with 239 additions and 207 deletions

View File

@ -941,203 +941,79 @@ pub fn softcast_data_to_type_otherwise(
) -> Term<Name> { ) -> Term<Name> {
let uplc_type = field_type.get_uplc_type(); let uplc_type = field_type.get_uplc_type();
let then = then.lambda(name); let just_then = then.clone();
match uplc_type { let then_delayed = |v| then.lambda(name).apply(v).delay();
Some(UplcType::Integer) => Term::var("__val")
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
then.apply(Term::un_i_data().apply(Term::var("__val")))
.delay(),
otherwise_delayed.clone(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::ByteString) => Term::var("__val")
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
then.apply(Term::un_b_data().apply(Term::var("__val")))
.delay(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::String) => Term::var("__val")
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
then.apply(Term::decode_utf8().apply(Term::un_b_data().apply(Term::var("__val"))))
.delay(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::List(_)) if field_type.is_map() => Term::var("__val") value.as_var("__val", |val| match uplc_type {
.choose_data( None => val
otherwise_delayed.clone(), .choose_data_constr(then_delayed, &otherwise_delayed)
then.apply(Term::unmap_data().apply(Term::var("__val"))) .force(),
.delay(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::List(_)) => Term::var("__val")
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
then.apply(Term::unlist_data().apply(Term::var("__val")))
.delay(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::Bls12_381G1Element) => Term::var("__val") Some(UplcType::Data) => just_then,
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
then.apply(
Term::bls12_381_g1_uncompress()
.apply(Term::un_b_data().apply(Term::var("__val"))),
)
.delay(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::Bls12_381G2Element) => Term::var("__val")
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
then.apply(
Term::bls12_381_g2_uncompress()
.apply(Term::un_b_data().apply(Term::var("__val"))),
)
.delay(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::Bls12_381MlResult) => panic!("ML Result not supported"),
Some(UplcType::Pair(_, _)) => Term::var("__val")
.choose_data(
otherwise_delayed.clone(),
otherwise_delayed.clone(),
Term::var("__list_data")
.choose_list(
otherwise_delayed.clone(),
Term::var("__tail")
.choose_list(
otherwise_delayed.clone(),
Term::tail_list()
.apply(Term::var("__tail"))
.choose_list(
then.apply(
Term::mk_pair_data()
.apply(
Term::head_list()
.apply(Term::var("__list_data")),
)
.apply(
Term::head_list().apply(Term::var("__tail")),
),
)
.delay(),
otherwise_delayed.clone(),
)
.force()
.delay(),
)
.force()
.lambda("__tail")
.apply(Term::tail_list().apply(Term::var("__list_data")))
.delay(),
)
.force()
.lambda("__list_data")
.apply(Term::unlist_data().apply(Term::var("__val")))
.delay(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::Bool) => Term::var("__val")
.choose_data(
Term::unwrap_bool_or(
Term::var("__val"),
|result| then.apply(result),
&otherwise_delayed,
)
.delay(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::Unit) => Term::var("__val")
.choose_data(
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(Term::var("__val"))))
.if_then_else(
Term::snd_pair()
.apply(Term::unconstr_data().apply(Term::var("__val")))
.choose_list(
then.apply(Term::unit()).delay(),
otherwise_delayed.clone(),
)
.force()
.delay(),
otherwise_delayed.clone(),
)
.force()
.delay(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
otherwise_delayed.clone(),
)
.force()
.lambda("__val")
.apply(value),
Some(UplcType::Data) => then.apply(value), Some(UplcType::Bls12_381MlResult) => {
// constr type unreachable!("attempted to cast Data into Bls12_381MlResult ?!")
None => Term::var("__val") }
.choose_data(
then.apply(Term::var("__val")).delay(), Some(UplcType::Integer) => val
otherwise_delayed.clone(), .choose_data_integer(then_delayed, &otherwise_delayed)
otherwise_delayed.clone(), .force(),
otherwise_delayed.clone(),
otherwise_delayed.clone(), Some(UplcType::ByteString) => val
.choose_data_bytearray(then_delayed, &otherwise_delayed)
.force(),
Some(UplcType::String) => val
.choose_data_bytearray(
|bytes| then_delayed(Term::decode_utf8().apply(bytes)),
&otherwise_delayed,
) )
.force() .force(),
.lambda("__val")
.apply(value), Some(UplcType::List(_)) if field_type.is_map() => val
} .choose_data_map(then_delayed, &otherwise_delayed)
.force(),
Some(UplcType::List(_)) => val
.choose_data_list(then_delayed, &otherwise_delayed)
.force(),
Some(UplcType::Bls12_381G1Element) => val
.choose_data_bytearray(
|bytes| then_delayed(Term::bls12_381_g1_uncompress().apply(bytes)),
&otherwise_delayed,
)
.force(),
Some(UplcType::Bls12_381G2Element) => val
.choose_data_bytearray(
|bytes| then_delayed(Term::bls12_381_g2_uncompress().apply(bytes)),
&otherwise_delayed,
)
.force(),
Some(UplcType::Pair(_, _)) => val
.choose_data_list(
|list| list.unwrap_pair_or(then_delayed, &otherwise_delayed),
&otherwise_delayed,
)
.force(),
Some(UplcType::Bool) => val
.choose_data_constr(
|constr| constr.unwrap_bool_or(then_delayed, &otherwise_delayed),
&otherwise_delayed,
)
.force(),
Some(UplcType::Unit) => val
.choose_data_constr(
|constr| constr.unwrap_void_or(then_delayed, &otherwise_delayed),
&otherwise_delayed,
)
.force(),
})
} }
pub fn convert_constants_to_data(constants: Vec<Rc<UplcConstant>>) -> Vec<UplcConstant> { pub fn convert_constants_to_data(constants: Vec<Rc<UplcConstant>>) -> Vec<UplcConstant> {

View File

@ -485,34 +485,190 @@ impl Term<Name> {
) )
} }
/// Introduce a let-binding for a given term. The callback receives a Term::Var
/// whose name matches the given 'var_name'. Handy to re-use a same var across
/// multiple lambda expressions.
///
/// ## Example
///
/// ```
/// value.as_var("__val", |val| {
/// val.do_something()
/// .do_another_thing()
/// })
/// ```
pub fn as_var<F>(self, var_name: &str, callback: F) -> Term<Name>
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
callback(Term::var(var_name)).lambda(var_name).apply(self)
}
/// Continue a computation provided that the current term is a Data-wrapped integer.
/// The 'callback' receives an integer constant Term as argument.
pub fn choose_data_integer<F>(self, callback: F, otherwise: &Term<Name>) -> Self
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
self.clone().choose_data(
otherwise.clone(),
otherwise.clone(),
otherwise.clone(),
callback(Term::un_i_data().apply(self)),
otherwise.clone(),
)
}
/// Continue a computation provided that the current term is a Data-wrapped
/// bytearray. The 'callback' receives a bytearray constant Term as argument.
pub fn choose_data_bytearray<F>(self, callback: F, otherwise: &Term<Name>) -> Self
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
self.clone().choose_data(
otherwise.clone(),
otherwise.clone(),
otherwise.clone(),
otherwise.clone(),
callback(Term::un_b_data().apply(self)),
)
}
/// Continue a computation provided that the current term is a Data-wrapped
/// list. The 'callback' receives a ProtoList Term as argument.
pub fn choose_data_list<F>(self, callback: F, otherwise: &Term<Name>) -> Self
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
self.clone().choose_data(
otherwise.clone(),
otherwise.clone(),
callback(Term::unlist_data().apply(self)),
otherwise.clone(),
otherwise.clone(),
)
}
/// Continue a computation provided that the current term is a Data-wrapped
/// list. The 'callback' receives a ProtoMap Term as argument.
pub fn choose_data_map<F>(self, callback: F, otherwise: &Term<Name>) -> Self
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
self.clone().choose_data(
otherwise.clone(),
callback(Term::unmap_data().apply(self)),
otherwise.clone(),
otherwise.clone(),
otherwise.clone(),
)
}
/// Continue a computation provided that the current term is a Data-wrapped
/// constr. The 'callback' receives a Data as argument.
pub fn choose_data_constr<F>(self, callback: F, otherwise: &Term<Name>) -> Self
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
self.clone().choose_data(
callback(self),
otherwise.clone(),
otherwise.clone(),
otherwise.clone(),
otherwise.clone(),
)
}
/// Convert an arbitrary 'term' into a bool term and pass it into a 'callback'. /// Convert an arbitrary 'term' into a bool term and pass it into a 'callback'.
/// Continue the execution 'otherwise' with a different branch. /// Continue the execution 'otherwise' with a different branch.
/// ///
/// Note that the 'otherwise' term as well as the callback's result are expected /// Note that the 'otherwise' term as well as the callback's result are expected
/// to be delayed terms. /// to be delayed terms.
pub fn unwrap_bool_or<F>(term: Term<Name>, callback: F, otherwise: &Term<Name>) -> Term<Name> pub fn unwrap_bool_or<F>(self, callback: F, otherwise: &Term<Name>) -> Term<Name>
where where
F: FnOnce(Term<Name>) -> Term<Name>, F: FnOnce(Term<Name>) -> Term<Name>,
{ {
Term::snd_pair() Term::unconstr_data()
.apply(Term::var("__pair__")) .apply(self)
.choose_list( .as_var("__pair__", |pair| {
Term::less_than_equals_integer() Term::snd_pair()
.apply(Term::integer(2.into())) .apply(pair.clone())
.apply(Term::fst_pair().apply(Term::var("__pair__"))) .choose_list(
.delayed_if_then_else( Term::less_than_equals_integer()
.apply(Term::integer(2.into()))
.apply(Term::fst_pair().apply(pair.clone()))
.if_then_else(
otherwise.clone(),
callback(
Term::equals_integer()
.apply(Term::fst_pair().apply(pair))
.apply(Term::integer(1.into())),
),
),
otherwise.clone(), otherwise.clone(),
callback(
Term::equals_integer()
.apply(Term::fst_pair().apply(Term::var("__pair__")))
.apply(Term::integer(1.into())),
),
) )
.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.
pub fn unwrap_void_or<F>(self, callback: F, otherwise: &Term<Name>) -> Term<Name>
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(self.clone())))
.if_then_else(
Term::snd_pair()
.apply(Term::unconstr_data().apply(self))
.choose_list(callback(Term::unit()), otherwise.clone())
.force()
.delay(), .delay(),
otherwise.clone(), otherwise.clone(),
) )
.force() .force()
.lambda("__pair__") }
.apply(Term::unconstr_data().apply(term))
/// 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.
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(list.clone());
list.unwrap_tail_or(
|tail| {
tail.as_var("__tail", |tail| {
let right = Term::head_list().apply(tail.clone());
tail.unwrap_tail_or(
|_| otherwise.clone(),
&callback(Term::mk_pair_data().apply(left).apply(right)),
)
})
},
otherwise,
)
})
}
/// Continue with the tail of a list, if any; or fallback 'otherwise'.
///
/// Note that the 'otherwise' term as well as the callback's result are expected
/// to be delayed terms.
pub fn unwrap_tail_or<F>(self, callback: F, otherwise: &Term<Name>) -> Term<Name>
where
F: FnOnce(Term<Name>) -> Term<Name>,
{
self.clone()
.choose_list(otherwise.clone(), callback(Term::tail_list().apply(self)))
} }
} }