change: traverse_with_tree now has a boolean to determine when with is called
fix: Opaque types are now properly handled in code gen (i.e. code gen functions, in datums/redeemers, in from data casts) chore: add specific nested opaque type tests to code gen
This commit is contained in:
parent
c6f764d2db
commit
084b900b2a
|
@ -23,10 +23,10 @@ use crate::{
|
||||||
builtins::{bool, data, int, void},
|
builtins::{bool, data, int, void},
|
||||||
expr::TypedExpr,
|
expr::TypedExpr,
|
||||||
gen_uplc::builder::{
|
gen_uplc::builder::{
|
||||||
convert_opaque_type, erase_opaque_type_operations, find_and_replace_generics,
|
check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations,
|
||||||
find_list_clause_or_default_first, get_arg_type_name, get_generic_id_and_type,
|
find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
|
||||||
get_variant_name, monomorphize, pattern_has_conditions, wrap_as_multi_validator,
|
get_generic_id_and_type, get_variant_name, monomorphize, pattern_has_conditions,
|
||||||
wrap_validator_condition, CodeGenFunction, SpecificClause,
|
wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction, SpecificClause,
|
||||||
},
|
},
|
||||||
tipo::{
|
tipo::{
|
||||||
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
||||||
|
@ -539,7 +539,13 @@ impl<'a> CodeGenerator<'a> {
|
||||||
index,
|
index,
|
||||||
record,
|
record,
|
||||||
..
|
..
|
||||||
} => AirTree::record_access(*index, tipo.clone(), self.build(record)),
|
} => {
|
||||||
|
if check_replaceable_opaque_type(&record.tipo(), &self.data_types) {
|
||||||
|
self.build(record)
|
||||||
|
} else {
|
||||||
|
AirTree::record_access(*index, tipo.clone(), self.build(record))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypedExpr::ModuleSelect {
|
TypedExpr::ModuleSelect {
|
||||||
tipo,
|
tipo,
|
||||||
|
@ -1013,7 +1019,11 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
// This `value` is either value param that was passed in or
|
// This `value` is either value param that was passed in or
|
||||||
// local var
|
// local var
|
||||||
sequence.push(AirTree::fields_expose(indices, props.full_check, value));
|
if check_replaceable_opaque_type(tipo, &self.data_types) {
|
||||||
|
sequence.push(AirTree::let_assignment(&indices[0].1, value));
|
||||||
|
} else {
|
||||||
|
sequence.push(AirTree::fields_expose(indices, props.full_check, value));
|
||||||
|
}
|
||||||
|
|
||||||
sequence.append(
|
sequence.append(
|
||||||
&mut fields
|
&mut fields
|
||||||
|
@ -1116,6 +1126,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
location: Span,
|
location: Span,
|
||||||
) -> AirTree {
|
) -> AirTree {
|
||||||
assert!(tipo.get_generic().is_none());
|
assert!(tipo.get_generic().is_none());
|
||||||
|
let tipo = &convert_opaque_type(tipo, &self.data_types);
|
||||||
|
|
||||||
if tipo.is_primitive() {
|
if tipo.is_primitive() {
|
||||||
// Since we would return void anyway and ignore then we can just return value here and ignore
|
// Since we would return void anyway and ignore then we can just return value here and ignore
|
||||||
|
@ -2158,11 +2169,25 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let mut air_fields = fields.into_iter().map(|(_, _, _, val)| val).collect_vec();
|
let mut air_fields = fields.into_iter().map(|(_, _, _, val)| val).collect_vec();
|
||||||
|
|
||||||
let field_assign = AirTree::fields_expose(
|
let field_assign =
|
||||||
indices,
|
if check_replaceable_opaque_type(subject_tipo, &self.data_types) {
|
||||||
false,
|
AirTree::let_assignment(
|
||||||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
&indices[0].1,
|
||||||
);
|
AirTree::local_var(
|
||||||
|
props.clause_var_name.clone(),
|
||||||
|
subject_tipo.clone(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AirTree::fields_expose(
|
||||||
|
indices,
|
||||||
|
false,
|
||||||
|
AirTree::local_var(
|
||||||
|
props.clause_var_name.clone(),
|
||||||
|
subject_tipo.clone(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let mut sequence = vec![field_assign];
|
let mut sequence = vec![field_assign];
|
||||||
|
|
||||||
|
@ -2530,9 +2555,12 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let mut validator_hoistable;
|
let mut validator_hoistable;
|
||||||
|
|
||||||
// TODO change subsequent tree traversals to be more like a stream.
|
// TODO change subsequent tree traversals to be more like a stream.
|
||||||
air_tree.traverse_tree_with(&mut |air_tree: &mut AirTree, _| {
|
air_tree.traverse_tree_with(
|
||||||
erase_opaque_type_operations(air_tree, &self.data_types);
|
&mut |air_tree: &mut AirTree, _| {
|
||||||
});
|
erase_opaque_type_operations(air_tree, &self.data_types);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
self.find_function_vars_and_depth(
|
self.find_function_vars_and_depth(
|
||||||
&mut air_tree,
|
&mut air_tree,
|
||||||
|
@ -2964,7 +2992,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let function_def = self.functions.get(&generic_function_key);
|
let function_def = self.functions.get(&generic_function_key);
|
||||||
|
|
||||||
let Some(function_def) = function_def else {
|
let Some(function_def) = function_def
|
||||||
|
else {
|
||||||
let code_gen_func = self
|
let code_gen_func = self
|
||||||
.code_gen_functions
|
.code_gen_functions
|
||||||
.get(&generic_function_key.function_name)
|
.get(&generic_function_key.function_name)
|
||||||
|
@ -2988,12 +3017,21 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let mut function_variant_path = IndexMap::new();
|
let mut function_variant_path = IndexMap::new();
|
||||||
|
|
||||||
|
let mut body = body.clone();
|
||||||
|
|
||||||
|
body.traverse_tree_with(
|
||||||
|
&mut |air_tree, _| {
|
||||||
|
erase_opaque_type_operations(air_tree, &self.data_types);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
function_variant_path.insert(
|
function_variant_path.insert(
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
(
|
(
|
||||||
tree_path.clone(),
|
tree_path.clone(),
|
||||||
UserFunction::Function {
|
UserFunction::Function {
|
||||||
body: body.clone(),
|
body,
|
||||||
deps: vec![],
|
deps: vec![],
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
},
|
},
|
||||||
|
@ -3067,10 +3105,13 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let mut function_air_tree_body = self.build(&function_def.body);
|
let mut function_air_tree_body = self.build(&function_def.body);
|
||||||
|
|
||||||
function_air_tree_body.traverse_tree_with(&mut |air_tree, _| {
|
function_air_tree_body.traverse_tree_with(
|
||||||
erase_opaque_type_operations(air_tree, &self.data_types);
|
&mut |air_tree, _| {
|
||||||
monomorphize(air_tree, &mono_types);
|
erase_opaque_type_operations(air_tree, &self.data_types);
|
||||||
});
|
monomorphize(air_tree, &mono_types);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
func_variants.insert(
|
func_variants.insert(
|
||||||
variant,
|
variant,
|
||||||
|
@ -3093,10 +3134,13 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let mut function_air_tree_body = self.build(&function_def.body);
|
let mut function_air_tree_body = self.build(&function_def.body);
|
||||||
|
|
||||||
function_air_tree_body.traverse_tree_with(&mut |air_tree, _| {
|
function_air_tree_body.traverse_tree_with(
|
||||||
erase_opaque_type_operations(air_tree, &self.data_types);
|
&mut |air_tree, _| {
|
||||||
monomorphize(air_tree, &mono_types);
|
erase_opaque_type_operations(air_tree, &self.data_types);
|
||||||
});
|
monomorphize(air_tree, &mono_types);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
let mut function_variant_path = IndexMap::new();
|
let mut function_variant_path = IndexMap::new();
|
||||||
|
|
||||||
|
@ -3116,6 +3160,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -542,37 +542,14 @@ pub fn erase_opaque_type_operations(
|
||||||
air_tree: &mut AirTree,
|
air_tree: &mut AirTree,
|
||||||
data_types: &IndexMap<DataTypeKey, &TypedDataType>,
|
data_types: &IndexMap<DataTypeKey, &TypedDataType>,
|
||||||
) {
|
) {
|
||||||
if let AirTree::Expression(e) = air_tree {
|
if let AirTree::Expression(AirExpression::Constr { tipo, args, .. }) = air_tree {
|
||||||
match e {
|
if check_replaceable_opaque_type(tipo, data_types) {
|
||||||
AirExpression::Constr { tipo, args, .. } => {
|
let arg = args.pop().unwrap();
|
||||||
if check_replaceable_opaque_type(tipo, data_types) {
|
if let AirTree::Expression(AirExpression::CastToData { value, .. }) = arg {
|
||||||
let arg = args.pop().unwrap();
|
*air_tree = *value;
|
||||||
if let AirTree::Expression(AirExpression::CastToData { value, .. }) = arg {
|
} else {
|
||||||
*air_tree = *value;
|
*air_tree = arg;
|
||||||
} else {
|
|
||||||
*air_tree = arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AirExpression::RecordAccess { record, .. } => {
|
|
||||||
if check_replaceable_opaque_type(&record.return_type(), data_types) {
|
|
||||||
*air_tree = (**record).clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else if let AirTree::Statement {
|
|
||||||
statement: AirStatement::FieldsExpose {
|
|
||||||
record, indices, ..
|
|
||||||
},
|
|
||||||
hoisted_over: Some(hoisted_over),
|
|
||||||
} = air_tree
|
|
||||||
{
|
|
||||||
if check_replaceable_opaque_type(&record.return_type(), data_types) {
|
|
||||||
let name = indices[0].1.clone();
|
|
||||||
*air_tree = AirTree::let_assignment(name, (**record).clone())
|
|
||||||
.hoist_over((**hoisted_over).clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,17 +697,20 @@ pub fn modify_self_calls(
|
||||||
// TODO: this would be a lot simpler if each `Var`, `Let`, function argument, etc. had a unique identifier
|
// TODO: this would be a lot simpler if each `Var`, `Let`, function argument, etc. had a unique identifier
|
||||||
// rather than just a name; this would let us track if the Var passed to itself was the same value as the method argument
|
// rather than just a name; this would let us track if the Var passed to itself was the same value as the method argument
|
||||||
let mut shadowed_parameters: HashMap<String, TreePath> = HashMap::new();
|
let mut shadowed_parameters: HashMap<String, TreePath> = HashMap::new();
|
||||||
body.traverse_tree_with(&mut |air_tree: &mut AirTree, tree_path| {
|
body.traverse_tree_with(
|
||||||
identify_recursive_static_params(
|
&mut |air_tree: &mut AirTree, tree_path| {
|
||||||
air_tree,
|
identify_recursive_static_params(
|
||||||
tree_path,
|
air_tree,
|
||||||
func_params,
|
tree_path,
|
||||||
func_key,
|
func_params,
|
||||||
variant,
|
func_key,
|
||||||
&mut shadowed_parameters,
|
variant,
|
||||||
&mut potential_recursive_statics,
|
&mut shadowed_parameters,
|
||||||
);
|
&mut potential_recursive_statics,
|
||||||
});
|
);
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
// Find the index of any recursively static parameters,
|
// Find the index of any recursively static parameters,
|
||||||
// so we can remove them from the call-site of each recursive call
|
// so we can remove them from the call-site of each recursive call
|
||||||
|
@ -742,35 +722,38 @@ pub fn modify_self_calls(
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Modify any self calls to remove recursive static parameters and append `self` as a parameter for the recursion
|
// Modify any self calls to remove recursive static parameters and append `self` as a parameter for the recursion
|
||||||
body.traverse_tree_with(&mut |air_tree: &mut AirTree, _| {
|
body.traverse_tree_with(
|
||||||
if let AirTree::Expression(AirExpression::Call { func, args, .. }) = air_tree {
|
&mut |air_tree: &mut AirTree, _| {
|
||||||
if let AirTree::Expression(AirExpression::Var {
|
if let AirTree::Expression(AirExpression::Call { func, args, .. }) = air_tree {
|
||||||
constructor:
|
if let AirTree::Expression(AirExpression::Var {
|
||||||
ValueConstructor {
|
constructor:
|
||||||
variant: ValueConstructorVariant::ModuleFn { name, module, .. },
|
ValueConstructor {
|
||||||
..
|
variant: ValueConstructorVariant::ModuleFn { name, module, .. },
|
||||||
},
|
..
|
||||||
variant_name,
|
},
|
||||||
..
|
variant_name,
|
||||||
}) = func.as_ref()
|
..
|
||||||
{
|
}) = func.as_ref()
|
||||||
if name == &func_key.function_name
|
|
||||||
&& module == &func_key.module_name
|
|
||||||
&& variant == variant_name
|
|
||||||
{
|
{
|
||||||
// Remove any static-recursive-parameters, because they'll be bound statically
|
if name == &func_key.function_name
|
||||||
// above the recursive part of the function
|
&& module == &func_key.module_name
|
||||||
// note: assumes that static_recursive_params is sorted
|
&& variant == variant_name
|
||||||
for arg in recursive_static_indexes.iter().rev() {
|
{
|
||||||
args.remove(*arg);
|
// Remove any static-recursive-parameters, because they'll be bound statically
|
||||||
|
// above the recursive part of the function
|
||||||
|
// note: assumes that static_recursive_params is sorted
|
||||||
|
for arg in recursive_static_indexes.iter().rev() {
|
||||||
|
args.remove(*arg);
|
||||||
|
}
|
||||||
|
let mut new_args = vec![func.as_ref().clone()];
|
||||||
|
new_args.append(args);
|
||||||
|
*args = new_args;
|
||||||
}
|
}
|
||||||
let mut new_args = vec![func.as_ref().clone()];
|
|
||||||
new_args.append(args);
|
|
||||||
*args = new_args;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
true,
|
||||||
|
);
|
||||||
let recursive_nonstatics = func_params
|
let recursive_nonstatics = func_params
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|p| !potential_recursive_statics.contains(p))
|
.filter(|p| !potential_recursive_statics.contains(p))
|
||||||
|
|
|
@ -1362,9 +1362,13 @@ impl AirTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn traverse_tree_with(&mut self, with: &mut impl FnMut(&mut AirTree, &TreePath)) {
|
pub fn traverse_tree_with(
|
||||||
|
&mut self,
|
||||||
|
with: &mut impl FnMut(&mut AirTree, &TreePath),
|
||||||
|
apply_with_last: bool,
|
||||||
|
) {
|
||||||
let mut tree_path = TreePath::new();
|
let mut tree_path = TreePath::new();
|
||||||
self.do_traverse_tree_with(&mut tree_path, 0, 0, with);
|
self.do_traverse_tree_with(&mut tree_path, 0, 0, with, apply_with_last);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn traverse_tree_with_path(
|
pub fn traverse_tree_with_path(
|
||||||
|
@ -1373,8 +1377,9 @@ impl AirTree {
|
||||||
current_depth: usize,
|
current_depth: usize,
|
||||||
depth_index: usize,
|
depth_index: usize,
|
||||||
with: &mut impl FnMut(&mut AirTree, &TreePath),
|
with: &mut impl FnMut(&mut AirTree, &TreePath),
|
||||||
|
apply_with_last: bool,
|
||||||
) {
|
) {
|
||||||
self.do_traverse_tree_with(path, current_depth, depth_index, with);
|
self.do_traverse_tree_with(path, current_depth, depth_index, with, apply_with_last);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_traverse_tree_with(
|
fn do_traverse_tree_with(
|
||||||
|
@ -1383,6 +1388,7 @@ impl AirTree {
|
||||||
current_depth: usize,
|
current_depth: usize,
|
||||||
depth_index: usize,
|
depth_index: usize,
|
||||||
with: &mut impl FnMut(&mut AirTree, &TreePath),
|
with: &mut impl FnMut(&mut AirTree, &TreePath),
|
||||||
|
apply_with_last: bool,
|
||||||
) {
|
) {
|
||||||
let mut index_count = IndexCounter::new();
|
let mut index_count = IndexCounter::new();
|
||||||
tree_path.push(current_depth, depth_index);
|
tree_path.push(current_depth, depth_index);
|
||||||
|
@ -1395,6 +1401,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::DefineFunc { func_body, .. } => {
|
AirStatement::DefineFunc { func_body, .. } => {
|
||||||
|
@ -1403,6 +1410,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::AssertConstr { constr, .. } => {
|
AirStatement::AssertConstr { constr, .. } => {
|
||||||
|
@ -1411,6 +1419,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::AssertBool { value, .. } => {
|
AirStatement::AssertBool { value, .. } => {
|
||||||
|
@ -1419,6 +1428,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::ClauseGuard { pattern, .. } => {
|
AirStatement::ClauseGuard { pattern, .. } => {
|
||||||
|
@ -1427,6 +1437,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::ListClauseGuard { .. } => {}
|
AirStatement::ListClauseGuard { .. } => {}
|
||||||
|
@ -1437,6 +1448,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::ListAccessor { list, .. } => {
|
AirStatement::ListAccessor { list, .. } => {
|
||||||
|
@ -1445,6 +1457,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::ListExpose { .. } => {}
|
AirStatement::ListExpose { .. } => {}
|
||||||
|
@ -1454,6 +1467,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::NoOp => {}
|
AirStatement::NoOp => {}
|
||||||
|
@ -1463,6 +1477,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirStatement::ListEmpty { list } => {
|
AirStatement::ListEmpty { list } => {
|
||||||
|
@ -1471,12 +1486,15 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
with(self, tree_path);
|
if !apply_with_last {
|
||||||
|
with(self, tree_path);
|
||||||
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
AirTree::Statement {
|
AirTree::Statement {
|
||||||
|
@ -1488,6 +1506,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirTree::Expression(e) => match e {
|
AirTree::Expression(e) => match e {
|
||||||
|
@ -1498,6 +1517,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1508,6 +1528,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1517,6 +1538,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
|
@ -1525,6 +1547,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1534,6 +1557,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::Builtin { args, .. } => {
|
AirExpression::Builtin { args, .. } => {
|
||||||
|
@ -1543,6 +1567,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1552,6 +1577,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
right.do_traverse_tree_with(
|
right.do_traverse_tree_with(
|
||||||
|
@ -1559,6 +1585,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::UnOp { arg, .. } => {
|
AirExpression::UnOp { arg, .. } => {
|
||||||
|
@ -1567,6 +1594,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::CastFromData { value, .. } => {
|
AirExpression::CastFromData { value, .. } => {
|
||||||
|
@ -1575,6 +1603,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::CastToData { value, .. } => {
|
AirExpression::CastToData { value, .. } => {
|
||||||
|
@ -1583,6 +1612,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::When {
|
AirExpression::When {
|
||||||
|
@ -1593,6 +1623,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
clauses.do_traverse_tree_with(
|
clauses.do_traverse_tree_with(
|
||||||
|
@ -1600,6 +1631,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::Clause {
|
AirExpression::Clause {
|
||||||
|
@ -1613,6 +1645,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
then.do_traverse_tree_with(
|
then.do_traverse_tree_with(
|
||||||
|
@ -1620,6 +1653,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
otherwise.do_traverse_tree_with(
|
otherwise.do_traverse_tree_with(
|
||||||
|
@ -1627,6 +1661,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::ListClause {
|
AirExpression::ListClause {
|
||||||
|
@ -1637,6 +1672,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
otherwise.do_traverse_tree_with(
|
otherwise.do_traverse_tree_with(
|
||||||
|
@ -1644,6 +1680,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::WrapClause { then, otherwise } => {
|
AirExpression::WrapClause { then, otherwise } => {
|
||||||
|
@ -1652,6 +1689,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
otherwise.do_traverse_tree_with(
|
otherwise.do_traverse_tree_with(
|
||||||
|
@ -1659,6 +1697,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::TupleClause {
|
AirExpression::TupleClause {
|
||||||
|
@ -1669,6 +1708,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
otherwise.do_traverse_tree_with(
|
otherwise.do_traverse_tree_with(
|
||||||
|
@ -1676,6 +1716,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::Finally { pattern, then } => {
|
AirExpression::Finally { pattern, then } => {
|
||||||
|
@ -1684,6 +1725,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
then.do_traverse_tree_with(
|
then.do_traverse_tree_with(
|
||||||
|
@ -1691,6 +1733,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::If {
|
AirExpression::If {
|
||||||
|
@ -1704,6 +1747,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
then.do_traverse_tree_with(
|
then.do_traverse_tree_with(
|
||||||
|
@ -1711,6 +1755,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
otherwise.do_traverse_tree_with(
|
otherwise.do_traverse_tree_with(
|
||||||
|
@ -1718,6 +1763,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::Constr { args, .. } => {
|
AirExpression::Constr { args, .. } => {
|
||||||
|
@ -1727,6 +1773,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1736,6 +1783,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg.do_traverse_tree_with(
|
arg.do_traverse_tree_with(
|
||||||
|
@ -1743,6 +1791,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1752,6 +1801,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::TupleIndex { tuple, .. } => {
|
AirExpression::TupleIndex { tuple, .. } => {
|
||||||
|
@ -1760,6 +1810,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AirExpression::Trace { msg, then, .. } => {
|
AirExpression::Trace { msg, then, .. } => {
|
||||||
|
@ -1768,6 +1819,7 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
|
|
||||||
then.do_traverse_tree_with(
|
then.do_traverse_tree_with(
|
||||||
|
@ -1775,12 +1827,18 @@ impl AirTree {
|
||||||
current_depth + 1,
|
current_depth + 1,
|
||||||
index_count.next_number(),
|
index_count.next_number(),
|
||||||
with,
|
with,
|
||||||
|
apply_with_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
a => unreachable!("GOT THIS {:#?}", a),
|
a => unreachable!("GOT THIS {:#?}", a),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if apply_with_last {
|
||||||
|
with(self, tree_path);
|
||||||
|
}
|
||||||
|
|
||||||
tree_path.pop();
|
tree_path.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5077,3 +5077,268 @@ fn list_clause_with_assign2() {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn opaque_value_in_datum() {
|
||||||
|
let src = r#"
|
||||||
|
opaque type Value {
|
||||||
|
inner: Dict<Dict<Int>>
|
||||||
|
}
|
||||||
|
|
||||||
|
opaque type Dict<v> {
|
||||||
|
inner: List<(ByteArray, v)>
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dat {
|
||||||
|
c: Int,
|
||||||
|
a: Value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
validator {
|
||||||
|
fn spend(dat: Dat, red: Data, ctx: Data) {
|
||||||
|
let val = dat.a
|
||||||
|
|
||||||
|
expect [(_, amount)] = val.inner.inner
|
||||||
|
|
||||||
|
let final_amount = [(#"AA", 4)] |> Dict
|
||||||
|
|
||||||
|
final_amount == amount
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert_uplc(
|
||||||
|
src,
|
||||||
|
Term::tail_list()
|
||||||
|
.apply(Term::var("val"))
|
||||||
|
.delayed_choose_list(
|
||||||
|
Term::equals_data()
|
||||||
|
.apply(Term::map_data().apply(Term::var("final_amount")))
|
||||||
|
.apply(Term::map_data().apply(Term::var("amount")))
|
||||||
|
.lambda("final_amount")
|
||||||
|
.apply(Term::map_values(vec![Constant::ProtoPair(
|
||||||
|
Type::Data,
|
||||||
|
Type::Data,
|
||||||
|
Constant::Data(Data::bytestring(vec![170])).into(),
|
||||||
|
Constant::Data(Data::integer(4.into())).into(),
|
||||||
|
)]))
|
||||||
|
.lambda("amount")
|
||||||
|
.apply(
|
||||||
|
Term::unmap_data().apply(Term::snd_pair().apply(Term::var("tuple_item_0"))),
|
||||||
|
),
|
||||||
|
Term::Error.trace(Term::string(
|
||||||
|
"List/Tuple/Constr contains more items than expected",
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.lambda("tuple_item_0")
|
||||||
|
.apply(Term::head_list().apply(Term::var("val")))
|
||||||
|
.lambda("val")
|
||||||
|
.apply(
|
||||||
|
Term::unmap_data().apply(
|
||||||
|
Term::var(CONSTR_GET_FIELD)
|
||||||
|
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("dat")))
|
||||||
|
.apply(Term::integer(1.into())),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.delayed_if_else(Term::unit(), Term::Error)
|
||||||
|
.lambda("_")
|
||||||
|
.apply(
|
||||||
|
Term::equals_integer()
|
||||||
|
.apply(Term::integer(0.into()))
|
||||||
|
.apply(Term::var("subject"))
|
||||||
|
.delayed_if_else(
|
||||||
|
Term::tail_list()
|
||||||
|
.apply(Term::var("tail_1"))
|
||||||
|
.delayed_choose_list(
|
||||||
|
Term::unit().lambda("_").apply(
|
||||||
|
Term::var("expect_on_list").apply(Term::var("a")).apply(
|
||||||
|
Term::var("expect_on_list")
|
||||||
|
.apply(Term::var("pair_snd_outer"))
|
||||||
|
.apply(
|
||||||
|
Term::un_i_data()
|
||||||
|
.apply(
|
||||||
|
Term::snd_pair().apply(Term::var("pair")),
|
||||||
|
)
|
||||||
|
.lambda("pair_fst")
|
||||||
|
.apply(Term::un_b_data().apply(
|
||||||
|
Term::fst_pair().apply(Term::var("pair")),
|
||||||
|
))
|
||||||
|
.lambda("pair"),
|
||||||
|
)
|
||||||
|
.lambda("pair_snd_outer")
|
||||||
|
.apply(Term::unmap_data().apply(
|
||||||
|
Term::snd_pair().apply(Term::var("pair_outer")),
|
||||||
|
))
|
||||||
|
.lambda("pair_fst_outer")
|
||||||
|
.apply(Term::un_b_data().apply(
|
||||||
|
Term::fst_pair().apply(Term::var("pair_outer")),
|
||||||
|
))
|
||||||
|
.lambda("pair_outer"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Term::Error.trace(Term::string(
|
||||||
|
"List/Tuple/Constr contains more items than expected",
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.lambda("a")
|
||||||
|
.apply(
|
||||||
|
Term::unmap_data()
|
||||||
|
.apply(Term::head_list().apply(Term::var("tail_1"))),
|
||||||
|
)
|
||||||
|
.lambda("tail_1")
|
||||||
|
.apply(Term::tail_list().apply(Term::var("dat_fields")))
|
||||||
|
.lambda("c")
|
||||||
|
.apply(
|
||||||
|
Term::un_i_data()
|
||||||
|
.apply(Term::head_list().apply(Term::var("dat_fields"))),
|
||||||
|
)
|
||||||
|
.lambda("dat_fields")
|
||||||
|
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("param_0"))),
|
||||||
|
Term::Error
|
||||||
|
.trace(Term::string("Constr index did not match any type variant")),
|
||||||
|
)
|
||||||
|
.lambda("subject")
|
||||||
|
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("param_0")))
|
||||||
|
.lambda("param_0")
|
||||||
|
.lambda("expect_on_list")
|
||||||
|
.apply(
|
||||||
|
Term::var("expect_on_list")
|
||||||
|
.apply(Term::var("expect_on_list"))
|
||||||
|
.apply(Term::var("list_to_check"))
|
||||||
|
.lambda("expect_on_list")
|
||||||
|
.apply(
|
||||||
|
Term::var("list_to_check")
|
||||||
|
.delayed_choose_list(
|
||||||
|
Term::unit(),
|
||||||
|
Term::var("expect_on_list")
|
||||||
|
.apply(Term::var("expect_on_list"))
|
||||||
|
.apply(
|
||||||
|
Term::tail_list().apply(Term::var("list_to_check")),
|
||||||
|
)
|
||||||
|
.lambda("_")
|
||||||
|
.apply(Term::var("check_with").apply(
|
||||||
|
Term::head_list().apply(Term::var("list_to_check")),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.lambda("list_to_check")
|
||||||
|
.lambda("expect_on_list"),
|
||||||
|
)
|
||||||
|
.lambda("check_with")
|
||||||
|
.lambda("list_to_check"),
|
||||||
|
)
|
||||||
|
.apply(Term::var("dat")),
|
||||||
|
)
|
||||||
|
.lambda("ctx")
|
||||||
|
.lambda("red")
|
||||||
|
.lambda("dat")
|
||||||
|
.constr_get_field()
|
||||||
|
.constr_fields_exposer()
|
||||||
|
.constr_index_exposer(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn opaque_value_in_test() {
|
||||||
|
let src = r#"
|
||||||
|
pub opaque type Value {
|
||||||
|
inner: Dict<Dict<Int>>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub opaque type Dict<v> {
|
||||||
|
inner: List<(ByteArray, v)>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Dat {
|
||||||
|
c: Int,
|
||||||
|
a: Value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dat_new() -> Dat {
|
||||||
|
let v = Value { inner: Dict { inner: [("", [(#"aa", 4)] |> Dict)] } }
|
||||||
|
Dat {
|
||||||
|
c: 0,
|
||||||
|
a: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test spend() {
|
||||||
|
let dat = dat_new()
|
||||||
|
|
||||||
|
let val = dat.a
|
||||||
|
|
||||||
|
expect [(_, amount)] = val.inner.inner
|
||||||
|
|
||||||
|
let final_amount = [(#"AA", 4)] |> Dict
|
||||||
|
|
||||||
|
final_amount == amount
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert_uplc(
|
||||||
|
src,
|
||||||
|
Term::tail_list()
|
||||||
|
.apply(Term::var("val"))
|
||||||
|
.delayed_choose_list(
|
||||||
|
Term::equals_data()
|
||||||
|
.apply(Term::map_data().apply(Term::var("final_amount")))
|
||||||
|
.apply(Term::map_data().apply(Term::var("amount")))
|
||||||
|
.lambda("final_amount")
|
||||||
|
.apply(Term::map_values(vec![Constant::ProtoPair(
|
||||||
|
Type::Data,
|
||||||
|
Type::Data,
|
||||||
|
Constant::Data(Data::bytestring(vec![170])).into(),
|
||||||
|
Constant::Data(Data::integer(4.into())).into(),
|
||||||
|
)]))
|
||||||
|
.lambda("amount")
|
||||||
|
.apply(
|
||||||
|
Term::unmap_data().apply(Term::snd_pair().apply(Term::var("tuple_item_0"))),
|
||||||
|
),
|
||||||
|
Term::Error.trace(Term::string(
|
||||||
|
"List/Tuple/Constr contains more items than expected",
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.lambda("tuple_item_0")
|
||||||
|
.apply(Term::head_list().apply(Term::var("val")))
|
||||||
|
.lambda("val")
|
||||||
|
.apply(
|
||||||
|
Term::unmap_data().apply(
|
||||||
|
Term::var(CONSTR_GET_FIELD)
|
||||||
|
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("dat")))
|
||||||
|
.apply(Term::integer(1.into())),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.lambda("dat")
|
||||||
|
.apply(Term::Constant(
|
||||||
|
Constant::Data(Data::constr(
|
||||||
|
0,
|
||||||
|
vec![
|
||||||
|
Data::integer(0.into()),
|
||||||
|
Data::map(vec![(
|
||||||
|
Data::bytestring(vec![]),
|
||||||
|
Data::map(vec![(Data::bytestring(vec![170]), Data::integer(4.into()))]),
|
||||||
|
)]),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
|
.lambda("v")
|
||||||
|
.apply(Term::map_values(vec![Constant::ProtoPair(
|
||||||
|
Type::Data,
|
||||||
|
Type::Data,
|
||||||
|
Constant::Data(Data::bytestring(vec![])).into(),
|
||||||
|
Constant::Data(Data::map(vec![(
|
||||||
|
Data::bytestring(vec![170]),
|
||||||
|
Data::integer(4.into()),
|
||||||
|
)]))
|
||||||
|
.into(),
|
||||||
|
)]))
|
||||||
|
.constr_get_field()
|
||||||
|
.constr_fields_exposer()
|
||||||
|
.constr_index_exposer(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue