diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index 629822fa..aa224fe5 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -2346,7 +2346,7 @@ fn acceptance_test_26_foldr() { } #[test] -fn acceptance_test_27() { +fn acceptance_test_27_flat_map() { let src = r#" pub fn foldr(xs: List, f: fn(a, b) -> b, zero: b) -> b { when xs is { @@ -2487,33 +2487,33 @@ fn acceptance_test_27() { } #[test] -fn acceptance_test_30() { +fn acceptance_test_28_unique_empty_list() { 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 { + pub fn filter(xs: List, f: fn(a) -> Bool) -> List { when xs is { [] -> [] [x, ..rest] -> - concat(f(x), flat_map(rest, f)) + if f(x) { + [x, ..filter(rest, f)] + } else { + filter(rest, f) + } } } - test flat_map_2() { - flat_map([1, 2, 3], fn(a) { [a, a] }) == [1, 1, 2, 2, 3, 3] + pub fn unique(xs: List) -> List { + when xs is { + [] -> + [] + [x, ..rest] -> + [x, ..unique(filter(rest, fn(y) { y != x }))] + } } + + test unique_1() { + unique([]) == [] + } "#; assert_uplc( @@ -2521,67 +2521,171 @@ fn acceptance_test_30() { Term::equals_data() .apply( Term::list_data().apply( - Term::var("flat_map") - .lambda("flat_map") + Term::var("unique") + .lambda("unique") + .apply(Term::var("unique").apply(Term::var("unique"))) + .lambda("unique") .apply( - Term::var("flat_map") - .apply(Term::var("flat_map")) + Term::var("xs") + .delayed_choose_list( + Term::empty_list(), + Term::mk_cons() + .apply(Term::var("x")) + .apply( + Term::var("unique").apply(Term::var("unique")).apply( + Term::var("filter").apply(Term::var("rest")).apply( + Term::equals_data() + .apply(Term::var("y")) + .apply(Term::var("x")) + .if_then_else( + Term::bool(false), + Term::bool(true), + ) + .lambda("y"), + ), + ), + ) + .lambda("rest") + .apply(Term::tail_list().apply(Term::var("xs"))) + .lambda("x") + .apply(Term::head_list().apply(Term::var("xs"))), + ) + .lambda("xs") + .lambda("unique"), + ) + .lambda("filter") + .apply( + Term::var("filter") + .apply(Term::var("filter")) .apply(Term::var("xs")) - .lambda("flat_map") + .lambda("filter") .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")) + Term::var("f") + .apply(Term::var("x")) + .delayed_if_then_else( + Term::mk_cons().apply(Term::var("x")).apply( + Term::var("filter") + .apply(Term::var("filter")) + .apply(Term::var("rest")), + ), + Term::var("filter") + .apply(Term::var("filter")) .apply(Term::var("rest")), ) .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")), - )), + .apply(Term::head_list().apply(Term::var("xs"))), ) .lambda("xs") - .lambda("flat_map"), + .lambda("filter"), ) .lambda("f") .lambda("xs"), ) - .lambda("concat") + .apply(Term::empty_list()), + ), + ) + .apply(Term::data(Data::list(vec![]))), + false, + ); +} + +#[test] +fn acceptance_test_28_unique_list() { + let src = r#" + pub fn filter(xs: List, f: fn(a) -> Bool) -> List { + when xs is { + [] -> + [] + [x, ..rest] -> + if f(x) { + [x, ..filter(rest, f)] + } else { + filter(rest, f) + } + } + } + + pub fn unique(xs: List) -> List { + when xs is { + [] -> + [] + [x, ..rest] -> + [x, ..unique(filter(rest, fn(y) { y != x }))] + } + } + + test unique_1() { + unique([1,2,3,1]) == [1,2,3] + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply( + Term::list_data().apply( + Term::var("unique") + .lambda("unique") + .apply(Term::var("unique").apply(Term::var("unique"))) + .lambda("unique") .apply( - Term::var("foldr") - .apply(Term::var("left")) - .apply( + Term::var("xs") + .delayed_choose_list( + Term::empty_list(), Term::mk_cons() .apply(Term::i_data().apply(Term::var("x"))) - .apply(Term::var("xs")) - .lambda("xs") - .lambda("x"), + .apply( + Term::var("unique").apply(Term::var("unique")).apply( + Term::var("filter").apply(Term::var("rest")).apply( + Term::equals_integer() + .apply(Term::var("y")) + .apply(Term::var("x")) + .if_then_else( + Term::bool(false), + Term::bool(true), + ) + .lambda("y"), + ), + ), + ) + .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"))), + ), ) - .apply(Term::var("right")) - .lambda("right") - .lambda("left"), + .lambda("xs") + .lambda("unique"), ) - .lambda("foldr") + .lambda("filter") .apply( - Term::var("foldr") - .apply(Term::var("foldr")) + Term::var("filter") + .apply(Term::var("filter")) .apply(Term::var("xs")) - .lambda("foldr") + .lambda("filter") .apply( Term::var("xs") .delayed_choose_list( - Term::var("zero"), + Term::empty_list(), Term::var("f") .apply(Term::var("x")) - .apply( - Term::var("foldr") - .apply(Term::var("foldr")) + .delayed_if_then_else( + Term::mk_cons() + .apply(Term::i_data().apply(Term::var("x"))) + .apply( + Term::var("filter") + .apply(Term::var("filter")) + .apply(Term::var("rest")), + ), + Term::var("filter") + .apply(Term::var("filter")) .apply(Term::var("rest")), ) .lambda("rest") @@ -2592,9 +2696,8 @@ fn acceptance_test_30() { )), ) .lambda("xs") - .lambda("foldr"), + .lambda("filter"), ) - .lambda("zero") .lambda("f") .lambda("xs"), ) @@ -2602,31 +2705,173 @@ fn acceptance_test_30() { 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"), - ), + Constant::Data(Data::integer(1.into())), + ])), ), ) - .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())), + .apply(Term::data(Data::list(vec![ + Data::integer(1.into()), + Data::integer(2.into()), + Data::integer(3.into()), ]))), false, ); } +#[test] +fn acceptance_test_29_union() { + let src = r#" + pub opaque type AssocList { + inner: List<(key, value)>, + } + + pub fn new() -> AssocList { + AssocList { inner: [] } + } + + pub fn from_list(xs: List<(key, value)>) -> AssocList { + AssocList { inner: do_from_list(xs) } + } + + fn do_from_list(xs: List<(key, value)>) -> List<(key, value)> { + when xs is { + [] -> + [] + [(k, v), ..rest] -> + do_insert(do_from_list(rest), k, v) + } + } + + pub fn insert( + in m: AssocList, + key k: key, + value v: value, + ) -> AssocList { + AssocList { inner: do_insert(m.inner, k, v) } + } + + fn do_insert(elems: List<(key, value)>, k: key, v: value) -> List<(key, value)> { + when elems is { + [] -> + [(k, v)] + [(k2, v2), ..rest] -> + if k == k2 { + [(k, v), ..rest] + } else { + [(k2, v2), ..do_insert(rest, k, v)] + } + } + } + + pub fn union( + left: AssocList, + right: AssocList, + ) -> AssocList { + AssocList { inner: do_union(left.inner, right.inner) } + } + + fn do_union( + left: List<(key, value)>, + right: List<(key, value)>, + ) -> List<(key, value)> { + when left is { + [] -> + right + [(k, v), ..rest] -> + do_union(rest, do_insert(right, k, v)) + } + } + + fn fixture_1() { + new() + |> insert("foo", 42) + |> insert("bar", 14) + } + + test union_1() { + union(fixture_1(), new()) == fixture_1() + } + + "#; + + assert_uplc( + src, + Term::equals_data() + .apply( + Term::map_data().apply( + Term::var("union") + .apply(Term::map_values(vec![ + Constant::ProtoPair( + Type::Data, + Type::Data, + Constant::Data(Data::bytestring("foo".as_bytes().to_vec())).into(), + Constant::Data(Data::integer(42.into())).into(), + ), + Constant::ProtoPair( + Type::Data, + Type::Data, + Constant::Data(Data::bytestring("bar".as_bytes().to_vec())).into(), + Constant::Data(Data::integer(14.into())).into(), + ), + ])) + .apply(Term::empty_map()), + ), + ) + .apply(Term::data(Data::map(vec![ + ( + Data::bytestring("foo".as_bytes().to_vec()), + Data::integer(42.into()), + ), + ( + Data::bytestring("bar".as_bytes().to_vec()), + Data::integer(14.into()), + ), + ]))), + false, + ); +} + +#[test] +fn acceptance_test_30_abs() { + let src = r#" + pub fn abs(a: Int) -> Int { + if a < 0 { + -a + } else { + a + } + } + + test abs_1() { + abs(-14) == 14 + } + "#; + + assert_uplc( + src, + Term::equals_integer() + .apply( + Term::var("abs") + .lambda("abs") + .apply( + Term::less_than_integer() + .apply(Term::var("a")) + .apply(Term::integer(0.into())) + .delayed_if_then_else( + Term::subtract_integer() + .apply(Term::integer(0.into())) + .apply(Term::var("a")), + Term::var("a"), + ) + .lambda("a"), + ) + .apply(Term::integer((-14).into())), + ) + .apply(Term::integer(14.into())), + false, + ); +} + #[test] fn expect_empty_list_on_filled_list() { let src = r#"