diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index b90de927..fad597d4 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -3809,34 +3809,59 @@ impl<'a> CodeGenerator<'a> { ) .unwrap(); - let (constr_index, _) = data_type + let (constr_index, constr_type) = data_type .constructors .iter() .enumerate() .find(|(_, x)| x.name == *constr_name) .unwrap(); - let fields = Term::empty_list(); + let mut term = Term::empty_list(); - let mut term = Term::constr_data() - .apply(Term::integer(constr_index.try_into().unwrap())) - .apply(fields); + if constr_type.arguments.is_empty() { + term = Term::constr_data() + .apply(Term::integer(constr_index.try_into().unwrap())) + .apply(term); - let mut program: Program = Program { - version: (1, 0, 0), - term, - }; + let mut program: Program = Program { + version: (1, 0, 0), + term, + }; - let mut interner = Interner::new(); + let mut interner = Interner::new(); - interner.program(&mut program); + interner.program(&mut program); - let eval_program: Program = program.try_into().unwrap(); + let eval_program: Program = + program.try_into().unwrap(); - let evaluated_term: Term = - eval_program.eval(ExBudget::default()).result().unwrap(); - term = evaluated_term.try_into().unwrap(); + let evaluated_term: Term = + 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(builder::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); } } @@ -4569,9 +4594,11 @@ impl<'a> CodeGenerator<'a> { .. } => { let mut arg_vec = vec![]; + for _ in 0..count { arg_vec.push(arg_stack.pop().unwrap()); } + let mut term = Term::empty_list(); for (index, arg) in arg_vec.iter().enumerate().rev() { diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index e9a0f501..bde85174 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -2374,3 +2374,183 @@ fn acceptance_test_20_map_some() { false, ); } + +#[test] +fn acceptance_test_22_filter_map() { + let src = r#" + pub fn foldr(xs: List, f: fn(a, b) -> b, zero: b) -> b { + when xs is { + [] -> + zero + [x, ..rest] -> + f(x, foldr(rest, f, zero)) + } + } + + pub fn filter_map(xs: List, f: fn(a) -> Option) -> List { + foldr( + xs, + fn(x, ys) { + when f(x) is { + None -> + ys + Some(y) -> + [y, ..ys] + } + }, + [], + ) + } + + test filter_map_1() { + filter_map([], fn(_) { Some(43) }) == [] + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply( + Term::list_data().apply( + Term::var("filter_map") + .lambda("filter_map") + .apply( + Term::var("foldr") + .apply(Term::var("xs")) + .apply( + Term::equals_integer() + .apply(Term::integer(1.into())) + .apply(Term::var("subject_index")) + .delayed_if_else( + Term::var("ys"), + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("y"))) + .apply(Term::var("ys")) + .lambda("y") + .apply( + Term::un_i_data().apply( + Term::head_list() + .apply(Term::var("subject_fields")), + ), + ) + .lambda("subject_fields") + .apply( + Term::var(CONSTR_FIELDS_EXPOSER) + .apply(Term::var("subject")), + ), + ) + .lambda("subject_index") + .apply( + Term::var(CONSTR_INDEX_EXPOSER) + .apply(Term::var("subject")), + ) + .lambda("subject") + .apply(Term::var("f").apply(Term::var("x"))) + .lambda("ys") + .lambda("x"), + ) + .apply(Term::empty_list()) + .lambda("f") + .lambda("xs"), + ) + .lambda("foldr") + .apply(Term::var("foldr").apply(Term::var("foldr"))) + .lambda("foldr") + .apply( + Term::var("xs") + .delayed_choose_list( + Term::var("zero"), + Term::var("f") + .apply(Term::var("x")) + .apply( + Term::var("foldr") + .apply(Term::var("foldr")) + .apply(Term::var("rest")) + .apply(Term::var("f")) + .apply(Term::var("zero")), + ) + .lambda("rest") + .apply(Term::tail_list().apply(Term::var("xs"))) + .lambda("x") + .apply(Term::head_list().apply(Term::var("xs"))), + ) + .lambda("zero") + .lambda("f") + .lambda("xs") + .lambda("foldr"), + ) + .apply(Term::empty_list()) + .apply( + Term::data(Data::constr(0, vec![Data::integer(42.into())])).lambda("_"), + ), + ), + ) + .apply(Term::list_data().apply(Term::empty_list())) + .constr_get_field() + .constr_fields_exposer() + .constr_index_exposer(), + false, + ); +} + +#[test] +fn pass_constr_as_function() { + let src = r#" + type Make { + a: Int, + b: SubMake + } + + type SubMake { + c: Int + } + + fn hi(sm: SubMake, to_make: fn (Int, SubMake) -> Make) -> Make { + to_make(3, sm) + } + + test cry() { + Make(3, SubMake(1)) == hi(SubMake(1), Make) + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply(Term::data(Data::constr( + 0, + vec![ + Data::integer(3.into()), + Data::constr(0, vec![Data::integer(1.into())]), + ], + ))) + .apply( + Term::var("hi") + .lambda("hi") + .apply( + Term::var("to_make") + .apply(Term::integer(3.into())) + .apply(Term::var("sm")) + .lambda("to_make") + .lambda("sm"), + ) + .apply(Term::data(Data::constr(0, vec![Data::integer(1.into())]))) + .apply( + Term::constr_data() + .apply(Term::integer(0.into())) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply( + Term::mk_cons() + .apply(Term::var("b")) + .apply(Term::empty_list()), + ), + ) + .lambda("b") + .lambda("a"), + ), + ), + false, + ); +}