refactor: change codegen uplc to have more type safety

Also refactor list_access_to_uplc
This commit is contained in:
microproofs 2024-01-08 14:06:29 -05:00 committed by Kasey
parent 7992a50bec
commit 2216f387c3
2 changed files with 318 additions and 458 deletions

View File

@ -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,
} }
} }
} }

View File

@ -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]
))),
&current_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 &parameter_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 &parameter_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> {