diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index 1cf1587a..c2c6faaf 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -2118,6 +2118,429 @@ fn acceptance_test_24_map2() { ); } +#[test] +fn acceptance_test_25_void_equal() { + let src = r#" + test nil_1() { + Void == Void + } + "#; + + assert_uplc( + src, + Term::unit().choose_unit(Term::unit().choose_unit(Term::bool(true))), + false, + ); +} + +#[test] +fn acceptance_test_26_foldr() { + 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 concat(left: List, right: List) -> List { + foldr(left, fn(x, xs) { [x, ..xs] }, right) + } + + pub fn flat_map(xs: List, f: fn(a) -> List) -> List { + when xs is { + [] -> + [] + [x, ..rest] -> + concat(f(x), flat_map(rest, f)) + } + } + + test flat_map_2() { + flat_map([1, 2, 3], fn(a) { [a, a] }) == [1, 1, 2, 2, 3, 3] + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply( + Term::list_data().apply( + Term::var("flat_map") + .lambda("flat_map") + .apply(Term::var("flat_map").apply(Term::var("flat_map"))) + .lambda("flat_map") + .apply( + Term::var("xs") + .delayed_choose_list( + Term::empty_list(), + Term::var("concat") + .apply(Term::var("f").apply(Term::var("x"))) + .apply( + Term::var("flat_map") + .apply(Term::var("flat_map")) + .apply(Term::var("rest")) + .apply(Term::var("f")), + ) + .lambda("rest") + .apply(Term::tail_list().apply(Term::var("xs"))) + .lambda("x") + .apply( + Term::un_i_data() + .apply(Term::head_list().apply(Term::var("xs"))), + ), + ) + .lambda("f") + .lambda("xs") + .lambda("flat_map"), + ) + .lambda("concat") + .apply( + Term::var("foldr") + .apply(Term::var("left")) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("x"))) + .apply(Term::var("xs")) + .lambda("xs") + .lambda("x"), + ) + .apply(Term::var("right")) + .lambda("right") + .lambda("left"), + ) + .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::un_i_data() + .apply(Term::head_list().apply(Term::var("xs"))), + ), + ) + .lambda("zero") + .lambda("f") + .lambda("xs") + .lambda("foldr"), + ) + .apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ])) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply(Term::empty_list()), + ) + .lambda("a"), + ), + ), + ) + .apply(Term::list_data().apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + Constant::Data(Data::integer(3.into())), + ]))), + false, + ); +} + +#[test] +fn acceptance_test_27() { + 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 concat(left: List, right: List) -> List { + foldr(left, fn(x, xs) { [x, ..xs] }, right) + } + + pub fn flat_map(xs: List, f: fn(a) -> List) -> List { + when xs is { + [] -> + [] + [x, ..rest] -> + concat(f(x), flat_map(rest, f)) + } + } + + test flat_map_2() { + flat_map([1, 2, 3], fn(a) { [a, a] }) == [1, 1, 2, 2, 3, 3] + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply( + Term::list_data().apply( + Term::var("flat_map") + .lambda("flat_map") + .apply(Term::var("flat_map").apply(Term::var("flat_map"))) + .lambda("flat_map") + .apply( + Term::var("xs") + .delayed_choose_list( + Term::empty_list(), + Term::var("concat") + .apply(Term::var("f").apply(Term::var("x"))) + .apply( + Term::var("flat_map") + .apply(Term::var("flat_map")) + .apply(Term::var("rest")) + .apply(Term::var("f")), + ) + .lambda("rest") + .apply(Term::tail_list().apply(Term::var("xs"))) + .lambda("x") + .apply( + Term::un_i_data() + .apply(Term::head_list().apply(Term::var("xs"))), + ), + ) + .lambda("f") + .lambda("xs") + .lambda("flat_map"), + ) + .lambda("concat") + .apply( + Term::var("foldr") + .apply(Term::var("left")) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("x"))) + .apply(Term::var("xs")) + .lambda("xs") + .lambda("x"), + ) + .apply(Term::var("right")) + .lambda("right") + .lambda("left"), + ) + .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::un_i_data() + .apply(Term::head_list().apply(Term::var("xs"))), + ), + ) + .lambda("zero") + .lambda("f") + .lambda("xs") + .lambda("foldr"), + ) + .apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ])) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply(Term::empty_list()), + ) + .lambda("a"), + ), + ), + ) + .apply(Term::list_data().apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + Constant::Data(Data::integer(3.into())), + ]))), + false, + ); +} + +#[test] +fn acceptance_test_30() { + 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 concat(left: List, right: List) -> List { + foldr(left, fn(x, xs) { [x, ..xs] }, right) + } + + pub fn flat_map(xs: List, f: fn(a) -> List) -> List { + when xs is { + [] -> + [] + [x, ..rest] -> + concat(f(x), flat_map(rest, f)) + } + } + + test flat_map_2() { + flat_map([1, 2, 3], fn(a) { [a, a] }) == [1, 1, 2, 2, 3, 3] + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply( + Term::list_data().apply( + Term::var("flat_map") + .lambda("flat_map") + .apply(Term::var("flat_map").apply(Term::var("flat_map"))) + .lambda("flat_map") + .apply( + Term::var("xs") + .delayed_choose_list( + Term::empty_list(), + Term::var("concat") + .apply(Term::var("f").apply(Term::var("x"))) + .apply( + Term::var("flat_map") + .apply(Term::var("flat_map")) + .apply(Term::var("rest")) + .apply(Term::var("f")), + ) + .lambda("rest") + .apply(Term::tail_list().apply(Term::var("xs"))) + .lambda("x") + .apply( + Term::un_i_data() + .apply(Term::head_list().apply(Term::var("xs"))), + ), + ) + .lambda("f") + .lambda("xs") + .lambda("flat_map"), + ) + .lambda("concat") + .apply( + Term::var("foldr") + .apply(Term::var("left")) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("x"))) + .apply(Term::var("xs")) + .lambda("xs") + .lambda("x"), + ) + .apply(Term::var("right")) + .lambda("right") + .lambda("left"), + ) + .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::un_i_data() + .apply(Term::head_list().apply(Term::var("xs"))), + ), + ) + .lambda("zero") + .lambda("f") + .lambda("xs") + .lambda("foldr"), + ) + .apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ])) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("a"))) + .apply(Term::empty_list()), + ) + .lambda("a"), + ), + ), + ) + .apply(Term::list_data().apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + Constant::Data(Data::integer(3.into())), + ]))), + false, + ); +} + #[test] fn expect_empty_list_on_filled_list() { let src = r#" @@ -2501,6 +2924,80 @@ fn when_tuple_deconstruction() { ); } +#[test] +fn when_tuple_empty_lists() { + let src = r#" + test hi() { + let bucket1 = [1, 2, 3] + let bucket2 = [1, 5, 6] + let bye = + when (bucket1, bucket2) is { + ([], _) -> False + (_, []) -> False + ([a, ..], [b, ..]) -> a == b + } + bye + } + "#; + + assert_uplc( + src, + Term::var("bucket_tuple_fst") + .choose_list(Term::bool(false).delay(), Term::var("delayed_clause")) + .force() + .lambda("delayed_clause") + .apply( + Term::var("bucket_tuple_snd") + .choose_list(Term::bool(false).delay(), Term::var("delayed_clause")) + .force() + .lambda("delayed_clause") + .apply( + Term::equals_integer() + .apply(Term::var("a")) + .apply(Term::var("b")) + .lambda("b") + .apply( + Term::un_i_data() + .apply(Term::head_list().apply(Term::var("bucket_tuple_snd"))), + ) + .lambda("a") + .apply( + Term::un_i_data() + .apply(Term::head_list().apply(Term::var("bucket_tuple_fst"))), + ) + .delay(), + ) + .lambda("bucket_tuple_snd") + .apply( + Term::unlist_data() + .apply(Term::snd_pair().apply(Term::var("bucket_tuple"))), + ) + .delay(), + ) + .lambda("bucket_tuple_fst") + .apply(Term::unlist_data().apply(Term::fst_pair().apply(Term::var("bucket_tuple")))) + .lambda("bucket_tuple") + .apply( + Term::mk_pair_data() + .apply(Term::list_data().apply(Term::var("bucket1"))) + .apply(Term::list_data().apply(Term::var("bucket2"))), + ) + .lambda("bucket2") + .apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(5.into())), + Constant::Data(Data::integer(6.into())), + ])) + .lambda("bucket1") + .apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ])), + false, + ); +} + #[test] fn generic_validator_type_test() { let error_string = "List/Tuple/Constr contains more items than expected"; @@ -3376,6 +3873,116 @@ fn expect_head_no_tail() { ); } +#[test] +fn expect_head3_no_tail() { + let src = r#" + test hi() { + let a = [1, 2, 3] + expect [h, i, j] = a + h == h && i == i && j == j + } + "#; + + assert_uplc( + src, + Term::tail_list() + .apply(Term::var("tail_2")) + .delayed_choose_list( + Term::equals_integer() + .apply(Term::var("h")) + .apply(Term::var("h")) + .delayed_if_else( + Term::equals_integer() + .apply(Term::var("i")) + .apply(Term::var("i")), + Term::bool(false), + ) + .delayed_if_else( + Term::equals_integer() + .apply(Term::var("j")) + .apply(Term::var("j")), + Term::bool(false), + ), + Term::Error.trace(Term::string( + "List/Tuple/Constr contains more items than expected", + )), + ) + .lambda("j") + .apply(Term::un_i_data().apply(Term::head_list().apply(Term::var("tail_2")))) + .lambda("tail_2") + .apply(Term::tail_list().apply(Term::var("tail_1"))) + .lambda("i") + .apply(Term::un_i_data().apply(Term::head_list().apply(Term::var("tail_1")))) + .lambda("tail_1") + .apply(Term::tail_list().apply(Term::var("a"))) + .lambda("h") + .apply(Term::un_i_data().apply(Term::head_list().apply(Term::var("a")))) + .lambda("a") + .apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ])), + false, + ); +} + +#[test] +fn expect_head3_cast_data_no_tail() { + let src = r#" + test hi() { + let a: Data = [1, 2, 3] + expect [h, i, j]: List = a + h == h && i ==i && j == j + } + "#; + + assert_uplc( + src, + Term::tail_list() + .apply(Term::var("tail_2")) + .delayed_choose_list( + Term::equals_integer() + .apply(Term::var("h")) + .apply(Term::var("h")) + .delayed_if_else( + Term::equals_integer() + .apply(Term::var("i")) + .apply(Term::var("i")), + Term::bool(false), + ) + .delayed_if_else( + Term::equals_integer() + .apply(Term::var("j")) + .apply(Term::var("j")), + Term::bool(false), + ), + Term::Error.trace(Term::string( + "List/Tuple/Constr contains more items than expected", + )), + ) + .lambda("j") + .apply(Term::un_i_data().apply(Term::head_list().apply(Term::var("tail_2")))) + .lambda("tail_2") + .apply(Term::tail_list().apply(Term::var("tail_1"))) + .lambda("i") + .apply(Term::un_i_data().apply(Term::head_list().apply(Term::var("tail_1")))) + .lambda("tail_1") + .apply(Term::tail_list().apply(Term::var("unwrap_a"))) + .lambda("h") + .apply(Term::un_i_data().apply(Term::head_list().apply(Term::var("unwrap_a")))) + .lambda("unwrap_a") + .apply(Term::unlist_data().apply(Term::var("a"))) + .lambda("a") + .apply(Term::list_data().apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ]))), + false, + ); +} + #[test] fn expect_head_cast_data_no_tail() { let src = r#"