refactor: change codegen uplc to have more type safety
Also refactor list_access_to_uplc
This commit is contained in:
parent
7992a50bec
commit
2216f387c3
|
@ -3709,13 +3709,16 @@ impl<'a> CodeGenerator<'a> {
|
||||||
fn uplc_code_gen(&mut self, mut ir_stack: Vec<Air>) -> Term<Name> {
|
fn uplc_code_gen(&mut self, mut ir_stack: Vec<Air>) -> Term<Name> {
|
||||||
let mut arg_stack: Vec<Term<Name>> = vec![];
|
let mut arg_stack: Vec<Term<Name>> = vec![];
|
||||||
|
|
||||||
while let Some(ir_element) = ir_stack.pop() {
|
while let Some(air_element) = ir_stack.pop() {
|
||||||
self.gen_uplc(ir_element, &mut arg_stack);
|
let arg = self.gen_uplc(air_element, &mut arg_stack);
|
||||||
|
if let Some(arg) = arg {
|
||||||
|
arg_stack.push(arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
arg_stack.pop().unwrap()
|
arg_stack.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec<Term<Name>>) {
|
fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec<Term<Name>>) -> Option<Term<Name>> {
|
||||||
// Going to mark the changes made to code gen after air tree implementation
|
// Going to mark the changes made to code gen after air tree implementation
|
||||||
let error_term = if self.tracing && air_holds_msg(&ir) {
|
let error_term = if self.tracing && air_holds_msg(&ir) {
|
||||||
// In the case of an air that holds a msg and tracing is active
|
// In the case of an air that holds a msg and tracing is active
|
||||||
|
@ -3728,196 +3731,183 @@ impl<'a> CodeGenerator<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match ir {
|
match ir {
|
||||||
Air::Int { value } => {
|
Air::Int { value } => Some(Term::integer(value.parse().unwrap())),
|
||||||
arg_stack.push(Term::integer(value.parse().unwrap()));
|
Air::String { value } => Some(Term::string(value)),
|
||||||
}
|
Air::ByteArray { bytes } => Some(Term::byte_string(bytes)),
|
||||||
Air::String { value } => {
|
Air::Bool { value } => Some(Term::bool(value)),
|
||||||
arg_stack.push(Term::string(value));
|
|
||||||
}
|
|
||||||
Air::ByteArray { bytes } => {
|
|
||||||
arg_stack.push(Term::byte_string(bytes));
|
|
||||||
}
|
|
||||||
Air::Bool { value } => {
|
|
||||||
arg_stack.push(Term::bool(value));
|
|
||||||
}
|
|
||||||
Air::CurvePoint { point, .. } => match point {
|
Air::CurvePoint { point, .. } => match point {
|
||||||
Curve::Bls12_381(Bls12_381Point::G1(g1)) => arg_stack.push(Term::bls12_381_g1(g1)),
|
Curve::Bls12_381(Bls12_381Point::G1(g1)) => Some(Term::bls12_381_g1(g1)),
|
||||||
Curve::Bls12_381(Bls12_381Point::G2(g2)) => arg_stack.push(Term::bls12_381_g2(g2)),
|
Curve::Bls12_381(Bls12_381Point::G2(g2)) => Some(Term::bls12_381_g2(g2)),
|
||||||
},
|
},
|
||||||
Air::Var {
|
Air::Var {
|
||||||
name,
|
name,
|
||||||
constructor,
|
constructor,
|
||||||
variant_name,
|
variant_name,
|
||||||
} => {
|
} => match &constructor.variant {
|
||||||
match &constructor.variant {
|
ValueConstructorVariant::LocalVariable { .. } => Some(Term::Var(
|
||||||
ValueConstructorVariant::LocalVariable { .. } => arg_stack.push(Term::Var(
|
Name {
|
||||||
Name {
|
text: name,
|
||||||
text: name,
|
unique: 0.into(),
|
||||||
unique: 0.into(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
)),
|
|
||||||
ValueConstructorVariant::ModuleConstant { .. } => {
|
|
||||||
unreachable!("{:#?}, {}", constructor, name)
|
|
||||||
}
|
}
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
ValueConstructorVariant::ModuleConstant { .. } => {
|
||||||
|
unreachable!("{:#?}, {}", constructor, name)
|
||||||
|
}
|
||||||
|
|
||||||
ValueConstructorVariant::ModuleFn {
|
ValueConstructorVariant::ModuleFn {
|
||||||
builtin: Some(builtin),
|
builtin: Some(builtin),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let term = match builtin {
|
let term = match builtin {
|
||||||
DefaultFunction::IfThenElse
|
DefaultFunction::IfThenElse
|
||||||
| DefaultFunction::ChooseUnit
|
| DefaultFunction::ChooseUnit
|
||||||
| DefaultFunction::Trace
|
| DefaultFunction::Trace
|
||||||
| DefaultFunction::ChooseList
|
| DefaultFunction::ChooseList
|
||||||
| DefaultFunction::ChooseData
|
| DefaultFunction::ChooseData
|
||||||
| DefaultFunction::UnConstrData => {
|
| DefaultFunction::UnConstrData => {
|
||||||
builder::special_case_builtin(builtin, 0, vec![])
|
builder::special_case_builtin(builtin, 0, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultFunction::FstPair
|
DefaultFunction::FstPair
|
||||||
| DefaultFunction::SndPair
|
| DefaultFunction::SndPair
|
||||||
| DefaultFunction::HeadList => builder::undata_builtin(
|
| DefaultFunction::HeadList => builder::undata_builtin(
|
||||||
builtin,
|
builtin,
|
||||||
0,
|
0,
|
||||||
&constructor.tipo.return_type().unwrap(),
|
&constructor.tipo.return_type().unwrap(),
|
||||||
vec![],
|
vec![],
|
||||||
),
|
),
|
||||||
|
|
||||||
DefaultFunction::MkCons | DefaultFunction::MkPairData => {
|
DefaultFunction::MkCons | DefaultFunction::MkPairData => {
|
||||||
unimplemented!("MkCons and MkPairData should be handled by an anon function or using [] or ( a, b, .., z).\n")
|
unimplemented!("MkCons and MkPairData should be handled by an anon function or using [] or ( a, b, .., z).\n")
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut term: Term<Name> = (*builtin).into();
|
let mut term: Term<Name> = (*builtin).into();
|
||||||
|
|
||||||
term = builder::apply_builtin_forces(term, builtin.force_count());
|
term = builder::apply_builtin_forces(term, builtin.force_count());
|
||||||
|
|
||||||
term
|
term
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
Some(term)
|
||||||
|
}
|
||||||
|
ValueConstructorVariant::ModuleFn {
|
||||||
|
name: func_name,
|
||||||
|
module,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&(
|
||||||
|
FunctionAccessKey {
|
||||||
|
module_name: module.clone(),
|
||||||
|
function_name: func_name.clone(),
|
||||||
|
},
|
||||||
|
variant_name.clone(),
|
||||||
|
)) {
|
||||||
|
let cyclic_var_name = if cyclic_name.module_name.is_empty() {
|
||||||
|
cyclic_name.function_name.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}_{}", cyclic_name.module_name, cyclic_name.function_name)
|
||||||
};
|
};
|
||||||
arg_stack.push(term);
|
|
||||||
}
|
|
||||||
ValueConstructorVariant::ModuleFn {
|
|
||||||
name: func_name,
|
|
||||||
module,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&(
|
|
||||||
FunctionAccessKey {
|
|
||||||
module_name: module.clone(),
|
|
||||||
function_name: func_name.clone(),
|
|
||||||
},
|
|
||||||
variant_name.clone(),
|
|
||||||
)) {
|
|
||||||
let cyclic_var_name = if cyclic_name.module_name.is_empty() {
|
|
||||||
cyclic_name.function_name.to_string()
|
|
||||||
} else {
|
|
||||||
format!("{}_{}", cyclic_name.module_name, cyclic_name.function_name)
|
|
||||||
};
|
|
||||||
|
|
||||||
let index_name = names[*index].clone();
|
let index_name = names[*index].clone();
|
||||||
|
|
||||||
let mut arg_var = Term::var(index_name.clone());
|
let mut arg_var = Term::var(index_name.clone());
|
||||||
|
|
||||||
for name in names.iter().rev() {
|
for name in names.iter().rev() {
|
||||||
arg_var = arg_var.lambda(name);
|
arg_var = arg_var.lambda(name);
|
||||||
}
|
|
||||||
|
|
||||||
let term = Term::var(cyclic_var_name).apply(arg_var);
|
|
||||||
|
|
||||||
arg_stack.push(term);
|
|
||||||
} else {
|
|
||||||
let name = if (*func_name == name
|
|
||||||
|| name == format!("{module}_{func_name}"))
|
|
||||||
&& !module.is_empty()
|
|
||||||
{
|
|
||||||
format!("{module}_{func_name}{variant_name}")
|
|
||||||
} else {
|
|
||||||
format!("{func_name}{variant_name}")
|
|
||||||
};
|
|
||||||
|
|
||||||
arg_stack.push(Term::Var(
|
|
||||||
Name {
|
|
||||||
text: name,
|
|
||||||
unique: 0.into(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ValueConstructorVariant::Record {
|
|
||||||
name: constr_name, ..
|
|
||||||
} => {
|
|
||||||
if constructor.tipo.is_bool() {
|
|
||||||
arg_stack.push(Term::bool(constr_name == "True"));
|
|
||||||
} else if constructor.tipo.is_void() {
|
|
||||||
arg_stack.push(Term::Constant(UplcConstant::Unit.into()));
|
|
||||||
} else {
|
|
||||||
let data_type = builder::lookup_data_type_by_tipo(
|
|
||||||
&self.data_types,
|
|
||||||
&constructor.tipo,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let (constr_index, constr_type) = data_type
|
let term = Term::var(cyclic_var_name).apply(arg_var);
|
||||||
.constructors
|
|
||||||
.iter()
|
Some(term)
|
||||||
.enumerate()
|
} else {
|
||||||
.find(|(_, x)| x.name == *constr_name)
|
let name = if (*func_name == name
|
||||||
|
|| name == format!("{module}_{func_name}"))
|
||||||
|
&& !module.is_empty()
|
||||||
|
{
|
||||||
|
format!("{module}_{func_name}{variant_name}")
|
||||||
|
} else {
|
||||||
|
format!("{func_name}{variant_name}")
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Term::Var(
|
||||||
|
Name {
|
||||||
|
text: name,
|
||||||
|
unique: 0.into(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueConstructorVariant::Record {
|
||||||
|
name: constr_name, ..
|
||||||
|
} => {
|
||||||
|
if constructor.tipo.is_bool() {
|
||||||
|
Some(Term::bool(constr_name == "True"))
|
||||||
|
} else if constructor.tipo.is_void() {
|
||||||
|
Some(Term::Constant(UplcConstant::Unit.into()))
|
||||||
|
} else {
|
||||||
|
let data_type =
|
||||||
|
builder::lookup_data_type_by_tipo(&self.data_types, &constructor.tipo)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut term = Term::empty_list();
|
let (constr_index, constr_type) = data_type
|
||||||
|
.constructors
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, x)| x.name == *constr_name)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if constr_type.arguments.is_empty() {
|
let mut term = Term::empty_list();
|
||||||
term = Term::constr_data()
|
|
||||||
.apply(Term::integer(constr_index.try_into().unwrap()))
|
if constr_type.arguments.is_empty() {
|
||||||
|
term = Term::constr_data()
|
||||||
|
.apply(Term::integer(constr_index.try_into().unwrap()))
|
||||||
|
.apply(term);
|
||||||
|
|
||||||
|
let mut program: Program<Name> = Program {
|
||||||
|
version: (1, 0, 0),
|
||||||
|
term,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut interner = Interner::new();
|
||||||
|
|
||||||
|
interner.program(&mut program);
|
||||||
|
|
||||||
|
let eval_program: Program<NamedDeBruijn> = program.try_into().unwrap();
|
||||||
|
|
||||||
|
let evaluated_term: Term<NamedDeBruijn> =
|
||||||
|
eval_program.eval(ExBudget::default()).result().unwrap();
|
||||||
|
term = evaluated_term.try_into().unwrap();
|
||||||
|
} else {
|
||||||
|
for (index, arg) in constr_type.arguments.iter().enumerate().rev() {
|
||||||
|
term = Term::mk_cons()
|
||||||
|
.apply(convert_type_to_data(
|
||||||
|
Term::var(
|
||||||
|
arg.label
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| format!("arg_{index}")),
|
||||||
|
),
|
||||||
|
&arg.tipo,
|
||||||
|
))
|
||||||
.apply(term);
|
.apply(term);
|
||||||
|
|
||||||
let mut program: Program<Name> = Program {
|
|
||||||
version: (1, 0, 0),
|
|
||||||
term,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut interner = Interner::new();
|
|
||||||
|
|
||||||
interner.program(&mut program);
|
|
||||||
|
|
||||||
let eval_program: Program<NamedDeBruijn> =
|
|
||||||
program.try_into().unwrap();
|
|
||||||
|
|
||||||
let evaluated_term: Term<NamedDeBruijn> =
|
|
||||||
eval_program.eval(ExBudget::default()).result().unwrap();
|
|
||||||
term = evaluated_term.try_into().unwrap();
|
|
||||||
} else {
|
|
||||||
for (index, arg) in constr_type.arguments.iter().enumerate().rev() {
|
|
||||||
term = Term::mk_cons()
|
|
||||||
.apply(convert_type_to_data(
|
|
||||||
Term::var(
|
|
||||||
arg.label
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| format!("arg_{index}")),
|
|
||||||
),
|
|
||||||
&arg.tipo,
|
|
||||||
))
|
|
||||||
.apply(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
term = Term::constr_data()
|
|
||||||
.apply(Term::integer(constr_index.into()))
|
|
||||||
.apply(term);
|
|
||||||
|
|
||||||
for (index, arg) in constr_type.arguments.iter().enumerate().rev() {
|
|
||||||
term = term.lambda(
|
|
||||||
arg.label.clone().unwrap_or_else(|| format!("arg_{index}")),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
|
||||||
|
term = Term::constr_data()
|
||||||
|
.apply(Term::integer(constr_index.into()))
|
||||||
|
.apply(term);
|
||||||
|
|
||||||
|
for (index, arg) in constr_type.arguments.iter().enumerate().rev() {
|
||||||
|
term = term.lambda(
|
||||||
|
arg.label.clone().unwrap_or_else(|| format!("arg_{index}")),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some(term)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
},
|
||||||
Air::Void => arg_stack.push(Term::Constant(UplcConstant::Unit.into())),
|
Air::Void => Some(Term::Constant(UplcConstant::Unit.into())),
|
||||||
Air::List { count, tipo, tail } => {
|
Air::List { count, tipo, tail } => {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
|
|
||||||
|
@ -3978,7 +3968,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
arg_stack.push(list);
|
Some(list)
|
||||||
} else {
|
} else {
|
||||||
let mut term = if tail {
|
let mut term = if tail {
|
||||||
args.pop().unwrap()
|
args.pop().unwrap()
|
||||||
|
@ -3999,7 +3989,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
};
|
};
|
||||||
term = Term::mk_cons().apply(list_item).apply(term);
|
term = Term::mk_cons().apply(list_item).apply(term);
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::ListAccessor {
|
Air::ListAccessor {
|
||||||
|
@ -4020,11 +4010,9 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let mut id_list = vec![];
|
let mut id_list = vec![];
|
||||||
id_list.push(list_id);
|
id_list.push(list_id);
|
||||||
|
|
||||||
for _ in 0..names.len() {
|
names.iter().for_each(|_| {
|
||||||
id_list.push(self.id_gen.next());
|
id_list.push(self.id_gen.next());
|
||||||
}
|
});
|
||||||
|
|
||||||
let names_empty = names.is_empty();
|
|
||||||
|
|
||||||
let names_types = tipo
|
let names_types = tipo
|
||||||
.get_inner_types()
|
.get_inner_types()
|
||||||
|
@ -4032,30 +4020,21 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.cycle()
|
.cycle()
|
||||||
.take(names.len())
|
.take(names.len())
|
||||||
.zip(names)
|
.zip(names)
|
||||||
.map(|(tipo, name)| (name, tipo))
|
.zip(id_list)
|
||||||
|
.map(|((tipo, name), id)| (name, tipo, id))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
if !names_empty {
|
term = builder::list_access_to_uplc(
|
||||||
term = builder::list_access_to_uplc(
|
&names_types,
|
||||||
&names_types,
|
tail,
|
||||||
&id_list,
|
term,
|
||||||
tail,
|
is_expect && !tail,
|
||||||
0,
|
true,
|
||||||
term,
|
error_term,
|
||||||
is_expect && !tail,
|
)
|
||||||
true,
|
.apply(value);
|
||||||
error_term,
|
|
||||||
)
|
|
||||||
.apply(value);
|
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else if is_expect {
|
|
||||||
term = value.delayed_choose_list(term, error_term);
|
|
||||||
|
|
||||||
arg_stack.push(term);
|
|
||||||
} else {
|
|
||||||
arg_stack.push(term);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Air::ListExpose {
|
Air::ListExpose {
|
||||||
tail_head_names,
|
tail_head_names,
|
||||||
|
@ -4084,7 +4063,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
term = term.lambda(head_name).apply(head_list);
|
term = term.lambda(head_name).apply(head_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::Fn { params } => {
|
Air::Fn { params } => {
|
||||||
let mut term = arg_stack.pop().unwrap();
|
let mut term = arg_stack.pop().unwrap();
|
||||||
|
@ -4094,9 +4073,9 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.is_empty() {
|
if params.is_empty() {
|
||||||
arg_stack.push(term.delay())
|
Some(term.delay())
|
||||||
} else {
|
} else {
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::Call { count, .. } => {
|
Air::Call { count, .. } => {
|
||||||
|
@ -4108,7 +4087,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = term.apply(arg);
|
term = term.apply(arg);
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else {
|
} else {
|
||||||
let term = arg_stack.pop().unwrap();
|
let term = arg_stack.pop().unwrap();
|
||||||
|
|
||||||
|
@ -4154,9 +4133,9 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let evaluated_term: Term<NamedDeBruijn> =
|
let evaluated_term: Term<NamedDeBruijn> =
|
||||||
eval_program.eval(ExBudget::max()).result().unwrap();
|
eval_program.eval(ExBudget::max()).result().unwrap();
|
||||||
|
|
||||||
arg_stack.push(evaluated_term.try_into().unwrap());
|
Some(evaluated_term.try_into().unwrap())
|
||||||
} else {
|
} else {
|
||||||
arg_stack.push(term.force())
|
Some(term.force())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Shouldn't call anything other than var")
|
unreachable!("Shouldn't call anything other than var")
|
||||||
|
@ -4206,7 +4185,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::BinOp {
|
Air::BinOp {
|
||||||
name,
|
name,
|
||||||
|
@ -4244,15 +4223,13 @@ impl<'a> CodeGenerator<'a> {
|
||||||
right.if_then_else(Term::bool(false), Term::bool(true)),
|
right.if_then_else(Term::bool(false), Term::bool(true)),
|
||||||
);
|
);
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_map() {
|
} else if tipo.is_map() {
|
||||||
let term = builtin
|
let term = builtin
|
||||||
.apply(Term::map_data().apply(left))
|
.apply(Term::map_data().apply(left))
|
||||||
.apply(Term::map_data().apply(right));
|
.apply(Term::map_data().apply(right));
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_tuple()
|
} else if tipo.is_tuple()
|
||||||
&& matches!(tipo.get_uplc_type(), UplcType::Pair(_, _))
|
&& matches!(tipo.get_uplc_type(), UplcType::Pair(_, _))
|
||||||
{
|
{
|
||||||
|
@ -4264,19 +4241,17 @@ impl<'a> CodeGenerator<'a> {
|
||||||
Term::mk_cons().apply(right).apply(Term::empty_map()),
|
Term::mk_cons().apply(right).apply(Term::empty_map()),
|
||||||
));
|
));
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_list() || tipo.is_tuple() {
|
} else if tipo.is_list() || tipo.is_tuple() {
|
||||||
let term = builtin
|
let term = builtin
|
||||||
.apply(Term::list_data().apply(left))
|
.apply(Term::list_data().apply(left))
|
||||||
.apply(Term::list_data().apply(right));
|
.apply(Term::list_data().apply(right));
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_void() {
|
} else if tipo.is_void() {
|
||||||
let term = left.choose_unit(right.choose_unit(Term::bool(true)));
|
let term = left.choose_unit(right.choose_unit(Term::bool(true)));
|
||||||
arg_stack.push(term);
|
|
||||||
return;
|
return Some(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
builtin.apply(left).apply(right)
|
builtin.apply(left).apply(right)
|
||||||
|
@ -4290,16 +4265,14 @@ impl<'a> CodeGenerator<'a> {
|
||||||
right,
|
right,
|
||||||
);
|
);
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_map() {
|
} else if tipo.is_map() {
|
||||||
let term = builtin
|
let term = builtin
|
||||||
.apply(Term::map_data().apply(left))
|
.apply(Term::map_data().apply(left))
|
||||||
.apply(Term::map_data().apply(right))
|
.apply(Term::map_data().apply(right))
|
||||||
.if_then_else(Term::bool(false), Term::bool(true));
|
.if_then_else(Term::bool(false), Term::bool(true));
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_tuple()
|
} else if tipo.is_tuple()
|
||||||
&& matches!(tipo.get_uplc_type(), UplcType::Pair(_, _))
|
&& matches!(tipo.get_uplc_type(), UplcType::Pair(_, _))
|
||||||
{
|
{
|
||||||
|
@ -4312,19 +4285,16 @@ impl<'a> CodeGenerator<'a> {
|
||||||
))
|
))
|
||||||
.if_then_else(Term::bool(false), Term::bool(true));
|
.if_then_else(Term::bool(false), Term::bool(true));
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_list() || tipo.is_tuple() {
|
} else if tipo.is_list() || tipo.is_tuple() {
|
||||||
let term = builtin
|
let term = builtin
|
||||||
.apply(Term::list_data().apply(left))
|
.apply(Term::list_data().apply(left))
|
||||||
.apply(Term::list_data().apply(right))
|
.apply(Term::list_data().apply(right))
|
||||||
.if_then_else(Term::bool(false), Term::bool(true));
|
.if_then_else(Term::bool(false), Term::bool(true));
|
||||||
|
|
||||||
arg_stack.push(term);
|
return Some(term);
|
||||||
return;
|
|
||||||
} else if tipo.is_void() {
|
} else if tipo.is_void() {
|
||||||
arg_stack.push(Term::bool(false));
|
return Some(Term::bool(false));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builtin
|
builtin
|
||||||
|
@ -4358,7 +4328,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.apply(left)
|
.apply(left)
|
||||||
.apply(right),
|
.apply(right),
|
||||||
};
|
};
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::DefineFunc {
|
Air::DefineFunc {
|
||||||
func_name,
|
func_name,
|
||||||
|
@ -4388,7 +4358,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
if !recursive {
|
if !recursive {
|
||||||
term = term.lambda(func_name).apply(func_body);
|
term = term.lambda(func_name).apply(func_body);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else {
|
} else {
|
||||||
func_body = func_body.lambda(func_name.clone());
|
func_body = func_body.lambda(func_name.clone());
|
||||||
|
|
||||||
|
@ -4422,7 +4392,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
term = term.lambda(&func_name).apply(outer_func_body);
|
term = term.lambda(&func_name).apply(outer_func_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::DefineCyclicFuncs {
|
Air::DefineCyclicFuncs {
|
||||||
|
@ -4469,7 +4439,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.lambda(&func_name)
|
.lambda(&func_name)
|
||||||
.apply(cyclic_body.lambda("__chooser").lambda(func_name));
|
.apply(cyclic_body.lambda("__chooser").lambda(func_name));
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::Let { name } => {
|
Air::Let { name } => {
|
||||||
let arg = arg_stack.pop().unwrap();
|
let arg = arg_stack.pop().unwrap();
|
||||||
|
@ -4478,7 +4448,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = term.lambda(name).apply(arg);
|
term = term.lambda(name).apply(arg);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::CastFromData { tipo } => {
|
Air::CastFromData { tipo } => {
|
||||||
let mut term = arg_stack.pop().unwrap();
|
let mut term = arg_stack.pop().unwrap();
|
||||||
|
@ -4504,7 +4474,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
term = builder::convert_data_to_type(term, &tipo);
|
term = builder::convert_data_to_type(term, &tipo);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::CastToData { tipo } => {
|
Air::CastToData { tipo } => {
|
||||||
let mut term = arg_stack.pop().unwrap();
|
let mut term = arg_stack.pop().unwrap();
|
||||||
|
@ -4530,7 +4500,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
term = builder::convert_type_to_data(term, &tipo);
|
term = builder::convert_type_to_data(term, &tipo);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::AssertConstr { constr_index } => {
|
Air::AssertConstr { constr_index } => {
|
||||||
let constr = arg_stack.pop().unwrap();
|
let constr = arg_stack.pop().unwrap();
|
||||||
|
@ -4548,7 +4518,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
)
|
)
|
||||||
.delayed_if_then_else(term, error_term);
|
.delayed_if_then_else(term, error_term);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::AssertBool { is_true } => {
|
Air::AssertBool { is_true } => {
|
||||||
let value = arg_stack.pop().unwrap();
|
let value = arg_stack.pop().unwrap();
|
||||||
|
@ -4560,7 +4530,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
} else {
|
} else {
|
||||||
term = value.delayed_if_then_else(error_term, term)
|
term = value.delayed_if_then_else(error_term, term)
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::When {
|
Air::When {
|
||||||
subject_name,
|
subject_name,
|
||||||
|
@ -4590,7 +4560,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = term.lambda(subject_name).apply(subject);
|
term = term.lambda(subject_name).apply(subject);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::Clause {
|
Air::Clause {
|
||||||
subject_tipo: tipo,
|
subject_tipo: tipo,
|
||||||
|
@ -4661,7 +4631,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::ListClause {
|
Air::ListClause {
|
||||||
tail_name,
|
tail_name,
|
||||||
|
@ -4690,7 +4660,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
term = Term::var(tail_name).delayed_choose_list(body, arg);
|
term = Term::var(tail_name).delayed_choose_list(body, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::WrapClause => {
|
Air::WrapClause => {
|
||||||
// no longer need to pop off discard
|
// no longer need to pop off discard
|
||||||
|
@ -4699,7 +4669,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = term.lambda("__other_clauses_delayed").apply(arg.delay());
|
term = term.lambda("__other_clauses_delayed").apply(arg.delay());
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::TupleClause {
|
Air::TupleClause {
|
||||||
subject_tipo: tipo,
|
subject_tipo: tipo,
|
||||||
|
@ -4748,7 +4718,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::ClauseGuard {
|
Air::ClauseGuard {
|
||||||
subject_name,
|
subject_name,
|
||||||
|
@ -4770,7 +4740,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.if_then_else(term, then.delay())
|
.if_then_else(term, then.delay())
|
||||||
.force();
|
.force();
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else {
|
} else {
|
||||||
let condition = if tipo.is_int() {
|
let condition = if tipo.is_int() {
|
||||||
Term::equals_integer()
|
Term::equals_integer()
|
||||||
|
@ -4799,7 +4769,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let term = condition
|
let term = condition
|
||||||
.if_then_else(then.delay(), Term::var("__other_clauses_delayed"))
|
.if_then_else(then.delay(), Term::var("__other_clauses_delayed"))
|
||||||
.force();
|
.force();
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::ListClauseGuard {
|
Air::ListClauseGuard {
|
||||||
|
@ -4831,7 +4801,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.force();
|
.force();
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::TupleGuard {
|
Air::TupleGuard {
|
||||||
subject_tipo: tipo,
|
subject_tipo: tipo,
|
||||||
|
@ -4870,10 +4840,12 @@ impl<'a> CodeGenerator<'a> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::Finally => {
|
Air::Finally => {
|
||||||
let _clause = arg_stack.pop().unwrap();
|
let _clause = arg_stack.pop().unwrap();
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Air::If { .. } => {
|
Air::If { .. } => {
|
||||||
let condition = arg_stack.pop().unwrap();
|
let condition = arg_stack.pop().unwrap();
|
||||||
|
@ -4882,7 +4854,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = condition.delayed_if_then_else(then, term);
|
term = condition.delayed_if_then_else(then, term);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::Constr {
|
Air::Constr {
|
||||||
tag: constr_index,
|
tag: constr_index,
|
||||||
|
@ -4929,7 +4901,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
term = evaluated_term.try_into().unwrap();
|
term = evaluated_term.try_into().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::FieldsExpose { indices, is_expect } => {
|
Air::FieldsExpose { indices, is_expect } => {
|
||||||
let mut id_list = vec![];
|
let mut id_list = vec![];
|
||||||
|
@ -4941,24 +4913,26 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
id_list.push(list_id);
|
id_list.push(list_id);
|
||||||
|
|
||||||
for _ in 0..indices.len() {
|
indices.iter().for_each(|_| {
|
||||||
id_list.push(self.id_gen.next());
|
id_list.push(self.id_gen.next());
|
||||||
}
|
});
|
||||||
|
|
||||||
let current_index = 0;
|
|
||||||
|
|
||||||
let names_types = indices
|
let names_types = indices
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|item| (item.1, item.2))
|
.zip(id_list)
|
||||||
|
.map(|(item, id)| (item.1, item.2, id))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
if !indices.is_empty() {
|
let named_indices = names_types
|
||||||
|
.iter()
|
||||||
|
.skip_while(|(name, _, _)| name.is_empty())
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
if !named_indices.is_empty() || is_expect {
|
||||||
term = builder::list_access_to_uplc(
|
term = builder::list_access_to_uplc(
|
||||||
&names_types,
|
&names_types,
|
||||||
&id_list,
|
|
||||||
false,
|
false,
|
||||||
current_index,
|
|
||||||
term,
|
term,
|
||||||
is_expect,
|
is_expect,
|
||||||
false,
|
false,
|
||||||
|
@ -4973,19 +4947,10 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.apply(value),
|
.apply(value),
|
||||||
);
|
);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else if is_expect {
|
|
||||||
term = Term::var(
|
|
||||||
self.special_functions
|
|
||||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
|
|
||||||
)
|
|
||||||
.apply(value)
|
|
||||||
.delayed_choose_list(term, error_term);
|
|
||||||
|
|
||||||
arg_stack.push(term);
|
|
||||||
} else {
|
} else {
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Air::FieldsEmpty => {
|
Air::FieldsEmpty => {
|
||||||
let value = arg_stack.pop().unwrap();
|
let value = arg_stack.pop().unwrap();
|
||||||
|
@ -4999,7 +4964,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.apply(value)
|
.apply(value)
|
||||||
.delayed_choose_list(term, error_term);
|
.delayed_choose_list(term, error_term);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::ListEmpty => {
|
Air::ListEmpty => {
|
||||||
let value = arg_stack.pop().unwrap();
|
let value = arg_stack.pop().unwrap();
|
||||||
|
@ -5008,7 +4973,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = value.delayed_choose_list(term, error_term);
|
term = value.delayed_choose_list(term, error_term);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::Tuple { count, tipo } => {
|
Air::Tuple { count, tipo } => {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
|
@ -5040,12 +5005,12 @@ impl<'a> CodeGenerator<'a> {
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else {
|
} else {
|
||||||
let term = Term::Constant(
|
let term = Term::Constant(
|
||||||
UplcConstant::ProtoList(UplcType::Data, data_constants).into(),
|
UplcConstant::ProtoList(UplcType::Data, data_constants).into(),
|
||||||
);
|
);
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
} else if count == 2 {
|
} else if count == 2 {
|
||||||
let term = Term::mk_pair_data()
|
let term = Term::mk_pair_data()
|
||||||
|
@ -5058,7 +5023,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
&tuple_sub_types[1],
|
&tuple_sub_types[1],
|
||||||
));
|
));
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else {
|
} else {
|
||||||
let mut term = Term::empty_list();
|
let mut term = Term::empty_list();
|
||||||
for (arg, tipo) in args.into_iter().zip(tuple_sub_types.into_iter()).rev() {
|
for (arg, tipo) in args.into_iter().zip(tuple_sub_types.into_iter()).rev() {
|
||||||
|
@ -5066,7 +5031,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.apply(builder::convert_type_to_data(arg, &tipo))
|
.apply(builder::convert_type_to_data(arg, &tipo))
|
||||||
.apply(term);
|
.apply(term);
|
||||||
}
|
}
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::RecordUpdate {
|
Air::RecordUpdate {
|
||||||
|
@ -5160,7 +5125,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
.apply(record),
|
.apply(record),
|
||||||
);
|
);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::UnOp { op } => {
|
Air::UnOp { op } => {
|
||||||
let value = arg_stack.pop().unwrap();
|
let value = arg_stack.pop().unwrap();
|
||||||
|
@ -5184,7 +5149,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::TupleAccessor {
|
Air::TupleAccessor {
|
||||||
tipo,
|
tipo,
|
||||||
|
@ -5220,22 +5185,25 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
term = term.lambda(format!("__tuple_{list_id}")).apply(value);
|
term = term.lambda(format!("__tuple_{list_id}")).apply(value);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else if !names.is_empty() {
|
} else {
|
||||||
let mut id_list = vec![];
|
let mut id_list = vec![];
|
||||||
id_list.push(list_id);
|
id_list.push(list_id);
|
||||||
|
|
||||||
for _ in 0..names.len() {
|
names.iter().for_each(|_| {
|
||||||
id_list.push(self.id_gen.next());
|
id_list.push(self.id_gen.next());
|
||||||
}
|
});
|
||||||
|
|
||||||
let names_types = names.into_iter().zip(inner_types).collect_vec();
|
let names_types = names
|
||||||
|
.into_iter()
|
||||||
|
.zip(inner_types)
|
||||||
|
.zip(id_list)
|
||||||
|
.map(|((name, tipo), id)| (name, tipo, id))
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
term = builder::list_access_to_uplc(
|
term = builder::list_access_to_uplc(
|
||||||
&names_types,
|
&names_types,
|
||||||
&id_list,
|
|
||||||
false,
|
false,
|
||||||
0,
|
|
||||||
term,
|
term,
|
||||||
is_expect,
|
is_expect,
|
||||||
false,
|
false,
|
||||||
|
@ -5243,9 +5211,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
)
|
)
|
||||||
.apply(value);
|
.apply(value);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
} else {
|
|
||||||
unreachable!("HOW DID YOU DO THIS");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::Trace { .. } => {
|
Air::Trace { .. } => {
|
||||||
|
@ -5255,17 +5221,17 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let term = term.delayed_trace(text);
|
let term = term.delayed_trace(text);
|
||||||
|
|
||||||
arg_stack.push(term);
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::ErrorTerm { validator, .. } => {
|
Air::ErrorTerm { validator, .. } => {
|
||||||
if validator {
|
if validator {
|
||||||
arg_stack.push(Term::Error.apply(Term::Error.force()))
|
Some(Term::Error.apply(Term::Error.force()))
|
||||||
} else {
|
} else {
|
||||||
arg_stack.push(Term::Error);
|
Some(Term::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Air::NoOp => {}
|
Air::NoOp => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1402,189 +1402,83 @@ pub fn convert_type_to_data(term: Term<Name>, field_type: &Rc<Type>) -> Term<Nam
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn list_access_to_uplc(
|
pub fn list_access_to_uplc(
|
||||||
names_types: &[(String, Rc<Type>)],
|
names_types_ids: &[(String, Rc<Type>, u64)],
|
||||||
id_list: &[u64],
|
|
||||||
tail: bool,
|
tail: bool,
|
||||||
current_index: usize,
|
|
||||||
term: Term<Name>,
|
term: Term<Name>,
|
||||||
check_last_item: bool,
|
check_last_item: bool,
|
||||||
is_list_accessor: bool,
|
is_list_accessor: bool,
|
||||||
error_term: Term<Name>,
|
error_term: Term<Name>,
|
||||||
) -> Term<Name> {
|
) -> Term<Name> {
|
||||||
if let Some(((first, current_tipo), names_types)) = names_types.split_first() {
|
let names_len = names_types_ids.len();
|
||||||
let head_list =
|
|
||||||
if matches!(current_tipo.get_uplc_type(), UplcType::Pair(_, _)) && is_list_accessor {
|
|
||||||
Term::head_list().apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
convert_data_to_type(
|
|
||||||
Term::head_list().apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))),
|
|
||||||
¤t_tipo.to_owned(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if names_types.len() == 1 && tail {
|
let mut no_tailing_discards = names_types_ids
|
||||||
if first == "_" && names_types[0].0 == "_" {
|
.iter()
|
||||||
term.lambda("_")
|
.rev()
|
||||||
} else if first == "_" {
|
.skip_while(|(name, _, _)| name == "_")
|
||||||
term.lambda(&names_types[0].0)
|
.collect_vec();
|
||||||
.apply(Term::tail_list().apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))))
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
} else if names_types[0].0 == "_" {
|
|
||||||
term.lambda(first).apply(head_list).lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
term.lambda(&names_types[0].0)
|
|
||||||
.apply(Term::tail_list().apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))))
|
|
||||||
.lambda(first)
|
|
||||||
.apply(head_list)
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else if names_types.is_empty() {
|
|
||||||
if first == "_" {
|
|
||||||
if check_last_item {
|
|
||||||
Term::tail_list()
|
|
||||||
.apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
)))
|
|
||||||
.delayed_choose_list(term, error_term)
|
|
||||||
} else {
|
|
||||||
term
|
|
||||||
}
|
|
||||||
.lambda(if check_last_item {
|
|
||||||
format!("tail_index_{}_{}", current_index, id_list[current_index])
|
|
||||||
} else {
|
|
||||||
"_".to_string()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
if check_last_item {
|
|
||||||
Term::tail_list()
|
|
||||||
.apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
)))
|
|
||||||
.delayed_choose_list(term, error_term)
|
|
||||||
} else {
|
|
||||||
term
|
|
||||||
}
|
|
||||||
.lambda(first.clone())
|
|
||||||
.apply(head_list)
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else if first == "_" {
|
|
||||||
let mut list_access_inner = list_access_to_uplc(
|
|
||||||
names_types,
|
|
||||||
id_list,
|
|
||||||
tail,
|
|
||||||
current_index + 1,
|
|
||||||
term,
|
|
||||||
check_last_item,
|
|
||||||
is_list_accessor,
|
|
||||||
error_term,
|
|
||||||
);
|
|
||||||
|
|
||||||
list_access_inner = match &list_access_inner {
|
// If the the is just discards and check_last_item then we check for empty list
|
||||||
Term::Lambda {
|
if no_tailing_discards.is_empty() && !tail && check_last_item {
|
||||||
parameter_name,
|
return Term::var("empty_list")
|
||||||
body,
|
.delayed_choose_list(term, error_term)
|
||||||
} => {
|
.lambda("empty_list");
|
||||||
if ¶meter_name.text == "_" {
|
|
||||||
body.as_ref().clone()
|
|
||||||
} else {
|
|
||||||
list_access_inner
|
|
||||||
.apply(Term::tail_list().apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))))
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => list_access_inner,
|
|
||||||
};
|
|
||||||
|
|
||||||
match &list_access_inner {
|
|
||||||
Term::Lambda { .. } => list_access_inner,
|
|
||||||
_ => list_access_inner.lambda("_"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut list_access_inner = list_access_to_uplc(
|
|
||||||
names_types,
|
|
||||||
id_list,
|
|
||||||
tail,
|
|
||||||
current_index + 1,
|
|
||||||
term,
|
|
||||||
check_last_item,
|
|
||||||
is_list_accessor,
|
|
||||||
error_term,
|
|
||||||
);
|
|
||||||
|
|
||||||
list_access_inner = match &list_access_inner {
|
|
||||||
Term::Lambda {
|
|
||||||
parameter_name,
|
|
||||||
body,
|
|
||||||
} => {
|
|
||||||
if ¶meter_name.text == "_" {
|
|
||||||
body.as_ref()
|
|
||||||
.clone()
|
|
||||||
.lambda(first.clone())
|
|
||||||
.apply(head_list)
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
list_access_inner
|
|
||||||
.apply(Term::tail_list().apply(Term::var(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))))
|
|
||||||
.lambda(first.clone())
|
|
||||||
.apply(head_list)
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => list_access_inner
|
|
||||||
.lambda(first.clone())
|
|
||||||
.apply(head_list)
|
|
||||||
.lambda(format!(
|
|
||||||
"tail_index_{}_{}",
|
|
||||||
current_index, id_list[current_index]
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
list_access_inner
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
term
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reverse back to original order
|
||||||
|
no_tailing_discards.reverse();
|
||||||
|
|
||||||
|
let no_tailing_len = no_tailing_discards.len();
|
||||||
|
|
||||||
|
// If we cut off at least one element then that was tail and possibly some heads
|
||||||
|
let tail = tail && no_tailing_discards.len() == names_len;
|
||||||
|
|
||||||
|
no_tailing_discards.into_iter().enumerate().rev().fold(
|
||||||
|
term,
|
||||||
|
|acc, (index, (name, tipo, id))| {
|
||||||
|
let tail_name = format!("tail_index_{}_{}", index, id);
|
||||||
|
|
||||||
|
let head_list =
|
||||||
|
if matches!(tipo.get_uplc_type(), UplcType::Pair(_, _)) && is_list_accessor {
|
||||||
|
Term::head_list().apply(Term::var(tail_name.to_string()))
|
||||||
|
} else {
|
||||||
|
convert_data_to_type(
|
||||||
|
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||||
|
&tipo.to_owned(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle tail case
|
||||||
|
// name is guaranteed to not be discard at this point
|
||||||
|
if index == no_tailing_len - 1 && tail {
|
||||||
|
// simply lambda for tail name
|
||||||
|
acc.lambda(name)
|
||||||
|
} else if index == no_tailing_len - 1 {
|
||||||
|
// case for no tail
|
||||||
|
// name is guaranteed to not be discard at this point
|
||||||
|
|
||||||
|
if check_last_item {
|
||||||
|
Term::tail_list()
|
||||||
|
.apply(Term::var(tail_name.to_string()))
|
||||||
|
.delayed_choose_list(acc, error_term.clone())
|
||||||
|
.lambda(name)
|
||||||
|
.apply(head_list)
|
||||||
|
.lambda("tail_name")
|
||||||
|
} else {
|
||||||
|
acc.lambda(name)
|
||||||
|
.apply(head_list)
|
||||||
|
.lambda(tail_name.to_string())
|
||||||
|
}
|
||||||
|
} else if name == "_" {
|
||||||
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
||||||
|
.lambda(tail_name.to_string())
|
||||||
|
} else {
|
||||||
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
||||||
|
.lambda(name)
|
||||||
|
.apply(head_list)
|
||||||
|
.lambda(tail_name.to_string())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_builtin_forces(mut term: Term<Name>, force_count: u32) -> Term<Name> {
|
pub fn apply_builtin_forces(mut term: Term<Name>, force_count: u32) -> Term<Name> {
|
||||||
|
|
Loading…
Reference in New Issue