#[macro_use] extern crate pretty_assertions; #[macro_use] extern crate indoc; extern crate bumpalo; extern crate inkwell; extern crate libc; extern crate roc_gen; #[macro_use] mod helpers; #[cfg(test)] mod gen_list { use crate::helpers::with_larger_debug_stack; use roc_std::{RocList, RocStr}; #[test] fn roc_list_construction() { let list = RocList::from_slice(&[1i64; 23]); assert_eq!(&list, &list); } #[test] fn empty_list_literal() { assert_evals_to!("[]", RocList::from_slice(&[]), RocList); } #[test] fn list_literal_empty_record() { assert_evals_to!("[{}]", RocList::from_slice(&[()]), RocList<()>); } #[test] fn int_singleton_list_literal() { assert_evals_to!("[1, 2]", RocList::from_slice(&[1, 2]), RocList); } #[test] fn int_list_literal() { assert_evals_to!("[ 12, 9 ]", RocList::from_slice(&[12, 9]), RocList); assert_evals_to!( "[ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ]", RocList::from_slice(&[1i64; 23]), RocList ); } #[test] fn bool_list_literal() { // NOTE: make sure to explicitly declare the elements to be of type bool, or // use both True and False; only using one of them causes the list to in practice be // of type `List [ True ]` or `List [ False ]`, those are tag unions with one constructor // and not fields, and don't have a runtime representation. assert_evals_to!( indoc!( r#" false : Bool false = False [ false ] "# ), RocList::from_slice(&[false; 1]), RocList ); assert_evals_to!( "[ True, False, True ]", RocList::from_slice(&[true, false, true]), RocList ); assert_evals_to!( indoc!( r#" false : Bool false = False [false ] "# ), RocList::from_slice(&[false; 1]), RocList ); assert_evals_to!( indoc!( r#" true : Bool true = True List.repeat 23 true "# ), RocList::from_slice(&[true; 23]), RocList ); assert_evals_to!( indoc!( r#" true : Bool true = True List.repeat 23 { x: true, y: true } "# ), RocList::from_slice(&[[true, true]; 23]), RocList<[bool; 2]> ); assert_evals_to!( indoc!( r#" true : Bool true = True List.repeat 23 { x: true, y: true, a: true, b: true, c: true, d : true, e: true, f: true } "# ), RocList::from_slice(&[[true, true, true, true, true, true, true, true]; 23]), RocList<[bool; 8]> ); } #[test] fn variously_sized_list_literals() { assert_evals_to!("[]", RocList::from_slice(&[]), RocList); assert_evals_to!("[1]", RocList::from_slice(&[1]), RocList); assert_evals_to!("[1, 2]", RocList::from_slice(&[1, 2]), RocList); assert_evals_to!("[1, 2, 3]", RocList::from_slice(&[1, 2, 3]), RocList); assert_evals_to!( "[1, 2, 3, 4]", RocList::from_slice(&[1, 2, 3, 4]), RocList ); assert_evals_to!( "[1, 2, 3, 4, 5]", RocList::from_slice(&[1, 2, 3, 4, 5]), RocList ); } #[test] fn list_append() { assert_evals_to!( "List.append [1] 2", RocList::from_slice(&[1, 2]), RocList ); assert_evals_to!( "List.append [1, 1] 2", RocList::from_slice(&[1, 1, 2]), RocList ); } #[test] fn list_append_to_empty_list() { assert_evals_to!("List.append [] 3", RocList::from_slice(&[3]), RocList); } #[test] fn list_append_to_empty_list_of_int() { assert_evals_to!( indoc!( r#" initThrees : List I64 initThrees = [] List.append (List.append initThrees 3) 3 "# ), RocList::from_slice(&[3, 3]), RocList ); } #[test] fn list_append_bools() { assert_evals_to!( "List.append [ True, False ] True", RocList::from_slice(&[true, false, true]), RocList ); } #[test] fn list_append_longer_list() { assert_evals_to!( "List.append [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ] 23", RocList::from_slice(&[11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]), RocList ); } #[test] fn list_prepend() { assert_evals_to!("List.prepend [] 1", RocList::from_slice(&[1]), RocList); assert_evals_to!( "List.prepend [2] 1", RocList::from_slice(&[1, 2]), RocList ); assert_evals_to!( indoc!( r#" init : List I64 init = [] List.prepend (List.prepend init 4) 6 "# ), RocList::from_slice(&[6, 4]), RocList ); } #[test] fn list_prepend_bools() { assert_evals_to!( "List.prepend [ True, False ] True", RocList::from_slice(&[true, true, false]), RocList ); } #[test] fn list_prepend_big_list() { assert_evals_to!( "List.prepend [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 100, 100, 100, 100 ] 9", RocList::from_slice(&[ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 100, 100, 100, 100 ]), RocList ); } #[test] fn list_walk_backwards_empty_all_inline() { assert_evals_to!( indoc!( r#" List.walkBackwards [0x1] (\a, b -> a + b) 0 "# ), 1, i64 ); assert_evals_to!( indoc!( r#" empty : List I64 empty = [] List.walkBackwards empty (\a, b -> a + b) 0 "# ), 0, i64 ); } #[test] fn list_walk_backwards_with_str() { assert_evals_to!( r#"List.walkBackwards [ "x", "y", "z" ] Str.concat "<""#, RocStr::from("xyz<"), RocStr ); assert_evals_to!( r#"List.walkBackwards [ "Third", "Second", "First" ] Str.concat "Fourth""#, RocStr::from("ThirdSecondFirstFourth"), RocStr ); } #[test] fn list_walk_backwards_with_record() { assert_evals_to!( indoc!( r#" Bit : [ Zero, One ] byte : List Bit byte = [ Zero, One, Zero, One, Zero, Zero, One, Zero ] initialCounts = { zeroes: 0, ones: 0 } acc = \b, r -> when b is Zero -> { r & zeroes: r.zeroes + 1 } One -> { r & ones: r.ones + 1 } finalCounts = List.walkBackwards byte acc initialCounts finalCounts.ones * 10 + finalCounts.zeroes "# ), 35, i64 ); } #[test] fn list_walk_with_str() { assert_evals_to!( r#"List.walk [ "x", "y", "z" ] Str.concat "<""#, RocStr::from("zyx<"), RocStr ); assert_evals_to!( r#"List.walk [ "Third", "Second", "First" ] Str.concat "Fourth""#, RocStr::from("FirstSecondThirdFourth"), RocStr ); } #[test] fn list_walk_substraction() { assert_evals_to!(r#"List.walk [ 1, 2 ] Num.sub 1"#, 2, i64); } #[test] fn list_keep_if_empty_list_of_int() { assert_evals_to!( indoc!( r#" empty : List I64 empty = [] List.keepIf empty (\_ -> True) "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_keep_if_empty_list() { assert_evals_to!( indoc!( r#" alwaysTrue : I64 -> Bool alwaysTrue = \_ -> True List.keepIf [] alwaysTrue "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_keep_if_always_true_for_non_empty_list() { assert_evals_to!( indoc!( r#" alwaysTrue : I64 -> Bool alwaysTrue = \_ -> True oneThroughEight : List I64 oneThroughEight = [1,2,3,4,5,6,7,8] List.keepIf oneThroughEight alwaysTrue "# ), RocList::from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]), RocList ); } #[test] fn list_keep_if_always_false_for_non_empty_list() { assert_evals_to!( indoc!( r#" alwaysFalse : I64 -> Bool alwaysFalse = \_ -> False List.keepIf [1,2,3,4,5,6,7,8] alwaysFalse "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_keep_if_one() { assert_evals_to!( indoc!( r#" intIsLessThanThree : I64 -> Bool intIsLessThanThree = \i -> i < 3 List.keepIf [1,2,3,4,5,6,7,8] intIsLessThanThree "# ), RocList::from_slice(&[1, 2]), RocList ); } #[test] fn list_keep_if_str_is_hello() { assert_evals_to!( indoc!( r#" List.keepIf ["x", "y", "x"] (\x -> x == "x") "# ), RocList::from_slice(&[ RocStr::from_slice("x".as_bytes()), RocStr::from_slice("x".as_bytes()) ]), RocList ); } #[test] fn list_map_on_empty_list_with_int_layout() { assert_evals_to!( indoc!( r#" empty : List I64 empty = [] List.map empty (\x -> x) "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_map_on_non_empty_list() { assert_evals_to!( indoc!( r#" nonEmpty : List I64 nonEmpty = [ 1 ] List.map nonEmpty (\x -> x) "# ), RocList::from_slice(&[1]), RocList ); } #[test] fn list_map_changes_input() { assert_evals_to!( indoc!( r#" nonEmpty : List I64 nonEmpty = [ 1 ] List.map nonEmpty (\x -> x + 1) "# ), RocList::from_slice(&[2]), RocList ); } #[test] fn list_map_on_big_list() { assert_evals_to!( indoc!( r#" nonEmpty : List I64 nonEmpty = [ 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5 ] List.map nonEmpty (\x -> x * 2) "# ), RocList::from_slice(&[ 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10 ]), RocList ); } #[test] fn list_map_with_type_change() { assert_evals_to!( indoc!( r#" nonEmpty : List I64 nonEmpty = [ 1, 1, -4, 1, 2 ] List.map nonEmpty (\x -> x > 0) "# ), RocList::from_slice(&[true, true, false, true, true]), RocList ); } #[test] fn list_map_using_defined_function() { assert_evals_to!( indoc!( r#" nonEmpty : List I64 nonEmpty = [ 2, 2, -4, 2, 3 ] greaterThanOne : I64 -> Bool greaterThanOne = \i -> i > 1 List.map nonEmpty greaterThanOne "# ), RocList::from_slice(&[true, true, false, true, true]), RocList ); } #[test] fn list_map_all_inline() { assert_evals_to!( indoc!( r#" List.map [] (\x -> x > 0) "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_map_closure() { assert_evals_to!( indoc!( r#" pi : F64 pi = 3.14 single : List F64 single = [ 0 ] List.map single (\x -> x + pi) "# ), RocList::from_slice(&[3.14]), RocList ); } #[test] fn list_join_empty_list() { assert_evals_to!("List.join []", RocList::from_slice(&[]), RocList); } #[test] fn list_join_one_list() { assert_evals_to!( "List.join [ [1, 2, 3 ] ]", RocList::from_slice(&[1, 2, 3]), RocList ); } #[test] fn list_join_two_non_empty_lists() { assert_evals_to!( "List.join [ [1, 2, 3 ] , [4 ,5, 6] ]", RocList::from_slice(&[1, 2, 3, 4, 5, 6]), RocList ); } #[test] fn list_join_two_non_empty_lists_of_float() { assert_evals_to!( "List.join [ [ 1.2, 1.1 ], [ 2.1, 2.2 ] ]", RocList::from_slice(&[1.2, 1.1, 2.1, 2.2]), RocList ); } #[test] fn list_join_to_big_list() { assert_evals_to!( indoc!( r#" List.join [ [ 1.2, 1.1 ], [ 2.1, 2.2 ], [ 3.0, 4.0, 5.0, 6.1, 9.0 ], [ 3.0, 4.0, 5.0, 6.1, 9.0 ], [ 3.0, 4.0, 5.0, 6.1, 9.0 ], [ 3.0, 4.0, 5.0, 6.1, 9.0 ], [ 3.0, 4.0, 5.0, 6.1, 9.0 ] ] "# ), RocList::from_slice(&[ 1.2, 1.1, 2.1, 2.2, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0 ]), RocList ); } #[test] fn list_join_defined_empty_list() { assert_evals_to!( indoc!( r#" empty : List F64 empty = [] List.join [ [ 0.2, 11.11 ], empty ] "# ), RocList::from_slice(&[0.2, 11.11]), RocList ); } #[test] fn list_join_all_empty_lists() { assert_evals_to!( "List.join [ [], [], [] ]", RocList::from_slice(&[]), RocList ); } #[test] fn list_join_one_empty_list() { assert_evals_to!( "List.join [ [ 1.2, 1.1 ], [] ]", RocList::from_slice(&[1.2, 1.1]), RocList ); } #[test] fn list_single() { assert_evals_to!("List.single 1", RocList::from_slice(&[1]), RocList); assert_evals_to!("List.single 5.6", RocList::from_slice(&[5.6]), RocList); } #[test] fn list_repeat() { assert_evals_to!( "List.repeat 5 1", RocList::from_slice(&[1, 1, 1, 1, 1]), RocList ); assert_evals_to!( "List.repeat 4 2", RocList::from_slice(&[2, 2, 2, 2]), RocList ); assert_evals_to!("List.repeat 2 []", &[&[], &[]], &'static [&'static [i64]]); assert_evals_to!( indoc!( r#" noStrs : List Str noStrs = [] List.repeat 2 noStrs "# ), &[&[], &[]], &'static [&'static [i64]] ); assert_evals_to!( "List.repeat 15 4", RocList::from_slice(&[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]), RocList ); } #[test] fn list_reverse() { assert_evals_to!( "List.reverse [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]", RocList::from_slice(&[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]), RocList ); assert_evals_to!( "List.reverse [1, 2, 3]", RocList::from_slice(&[3, 2, 1]), RocList ); assert_evals_to!("List.reverse [4]", RocList::from_slice(&[4]), RocList); } #[test] fn list_reverse_empty_list_of_int() { assert_evals_to!( indoc!( r#" emptyList : List I64 emptyList = [] List.reverse emptyList "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_reverse_empty_list() { assert_evals_to!("List.reverse []", RocList::from_slice(&[]), RocList); } #[test] fn foobarbaz() { assert_evals_to!( indoc!( r#" firstList : List I64 firstList = [] secondList : List I64 secondList = [] List.concat firstList secondList "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_concat_two_empty_lists() { assert_evals_to!("List.concat [] []", RocList::from_slice(&[]), RocList); } #[test] fn list_concat_two_empty_lists_of_int() { assert_evals_to!( indoc!( r#" firstList : List I64 firstList = [] secondList : List I64 secondList = [] List.concat firstList secondList "# ), RocList::from_slice(&[]), RocList ); } #[test] fn list_concat_second_list_is_empty() { assert_evals_to!( "List.concat [ 12, 13 ] []", RocList::from_slice(&[12, 13]), RocList ); assert_evals_to!( "List.concat [ 34, 43 ] [ 64, 55, 66 ]", RocList::from_slice(&[34, 43, 64, 55, 66]), RocList ); } #[test] fn list_concat_first_list_is_empty() { assert_evals_to!( "List.concat [] [ 23, 24 ]", RocList::from_slice(&[23, 24]), RocList ); } #[test] fn list_concat_two_non_empty_lists() { assert_evals_to!( "List.concat [1, 2 ] [ 3, 4 ]", RocList::from_slice(&[1, 2, 3, 4]), RocList ); } #[test] fn list_concat_two_bigger_non_empty_lists() { assert_evals_to!( "List.concat [ 1.1, 2.2 ] [ 3.3, 4.4, 5.5 ]", RocList::from_slice(&[1.1, 2.2, 3.3, 4.4, 5.5]), RocList ); } fn assert_concat_worked(num_elems1: i64, num_elems2: i64) { let vec1: Vec = (0..num_elems1) .map(|i| 12345 % (i + num_elems1 + num_elems2 + 1)) .collect(); let vec2: Vec = (0..num_elems2) .map(|i| 54321 % (i + num_elems1 + num_elems2 + 1)) .collect(); let slice_str1 = format!("{:?}", vec1); let slice_str2 = format!("{:?}", vec2); let mut expected = vec1; expected.extend(vec2); assert_evals_to!( &format!("List.concat {} {}", slice_str1, slice_str2), RocList::from_slice(&expected), RocList ); } #[test] fn list_concat_empty_list() { assert_concat_worked(0, 0); assert_concat_worked(1, 0); assert_concat_worked(2, 0); assert_concat_worked(3, 0); assert_concat_worked(4, 0); assert_concat_worked(7, 0); assert_concat_worked(8, 0); assert_concat_worked(9, 0); assert_concat_worked(25, 0); assert_concat_worked(150, 0); assert_concat_worked(0, 1); assert_concat_worked(0, 2); assert_concat_worked(0, 3); assert_concat_worked(0, 4); assert_concat_worked(0, 7); assert_concat_worked(0, 8); assert_concat_worked(0, 9); assert_concat_worked(0, 25); assert_concat_worked(0, 150); } #[test] fn list_concat_nonempty_lists() { assert_concat_worked(1, 1); assert_concat_worked(1, 2); assert_concat_worked(1, 3); assert_concat_worked(2, 3); assert_concat_worked(2, 1); assert_concat_worked(2, 2); assert_concat_worked(3, 1); assert_concat_worked(3, 2); assert_concat_worked(2, 3); assert_concat_worked(3, 3); assert_concat_worked(4, 4); } #[test] fn list_concat_large() { with_larger_debug_stack(|| { // these values produce mono ASTs so large that // it can cause a stack overflow. This has been solved // for current code, but may become a problem again in the future. assert_concat_worked(150, 150); assert_concat_worked(129, 350); assert_concat_worked(350, 129); }) } #[test] fn empty_list_len() { assert_evals_to!("List.len []", 0, usize); } #[test] fn basic_int_list_len() { assert_evals_to!("List.len [ 12, 9, 6, 3 ]", 4, usize); } #[test] fn loaded_int_list_len() { assert_evals_to!( indoc!( r#" nums = [ 2, 4, 6 ] List.len nums "# ), 3, usize ); } #[test] fn fn_int_list_len() { assert_evals_to!( indoc!( r#" getLen = \list -> List.len list nums = [ 2, 4, 6, 8 ] getLen nums "# ), 4, usize ); } #[test] fn int_list_is_empty() { assert_evals_to!("List.isEmpty [ 12, 9, 6, 3 ]", false, bool); } #[test] fn empty_list_is_empty() { assert_evals_to!("List.isEmpty []", true, bool); } #[test] fn first_int_list() { assert_evals_to!( indoc!( r#" when List.first [ 12, 9, 6, 3 ] is Ok val -> val Err _ -> -1 "# ), 12, i64 ); } #[test] #[ignore] fn first_wildcard_empty_list() { assert_evals_to!( indoc!( r#" when List.first [] is Ok _ -> 5 Err _ -> -1 "# ), -1, i64 ); } #[test] fn first_empty_list() { assert_evals_to!( indoc!( r#" when List.first [] is Ok val -> val Err _ -> -1 "# ), -1, i64 ); } #[test] fn last_int_list() { assert_evals_to!( indoc!( r#" when List.last [ 12, 9, 6, 3 ] is Ok val -> val Err _ -> -1 "# ), 3, i64 ); } #[test] #[ignore] fn last_wildcard_empty_list() { assert_evals_to!( indoc!( r#" when List.last [] is Ok _ -> 5 Err _ -> -1 "# ), -1, i64 ); } #[test] fn last_empty_list() { assert_evals_to!( indoc!( r#" when List.last [] is Ok val -> val Err _ -> -1 "# ), -1, i64 ); } #[test] fn get_empty_list() { assert_evals_to!( indoc!( r#" when List.get [] 0 is Ok val -> val Err _ -> -1 "# ), -1, i64 ); } #[test] #[ignore] fn get_wildcard_empty_list() { assert_evals_to!( indoc!( r#" when List.get [] 0 is Ok _ -> 5 Err _ -> -1 "# ), -1, i64 ); } #[test] fn get_int_list_ok() { assert_evals_to!( indoc!( r#" when List.get [ 12, 9, 6 ] 1 is Ok val -> val Err _ -> -1 "# ), 9, i64 ); } #[test] fn get_int_list_oob() { assert_evals_to!( indoc!( r#" when List.get [ 12, 9, 6 ] 1000 is Ok val -> val Err _ -> -1 "# ), -1, i64 ); } #[test] fn get_set_unique_int_list() { assert_evals_to!( indoc!( r#" when List.get (List.set [ 12, 9, 7, 3 ] 1 42) 1 is Ok val -> val Err _ -> -1 "# ), 42, i64 ); } #[test] fn set_unique_int_list() { assert_evals_to!( "List.set [ 12, 9, 7, 1, 5 ] 2 33", RocList::from_slice(&[12, 9, 33, 1, 5]), RocList ); } #[test] fn set_unique_list_oob() { assert_evals_to!( "List.set [ 3, 17, 4.1 ] 1337 9.25", RocList::from_slice(&[3.0, 17.0, 4.1]), RocList ); } #[test] fn set_shared_int_list() { assert_evals_to!( indoc!( r#" wrapper = \shared -> # This should not mutate the original x = when List.get (List.set shared 1 7.7) 1 is Ok num -> num Err _ -> 0 y = when List.get shared 1 is Ok num -> num Err _ -> 0 { x, y } wrapper [ 2.1, 4.3 ] "# ), (7.7, 4.3), (f64, f64) ); } #[test] fn set_shared_list_oob() { assert_evals_to!( indoc!( r#" shared = [ 2, 4 ] # This List.set is out of bounds, and should have no effect x = when List.get (List.set shared 422 0) 1 is Ok num -> num Err _ -> 0 y = when List.get shared 1 is Ok num -> num Err _ -> 0 { x, y } "# ), (4, 4), (i64, i64) ); } #[test] fn get_unique_int_list() { assert_evals_to!( indoc!( r#" unique = [ 2, 4 ] when List.get unique 1 is Ok num -> num Err _ -> -1 "# ), 4, i64 ); } #[test] fn gen_wrap_len() { assert_evals_to!( indoc!( r#" wrapLen = \list -> [ List.len list ] wrapLen [ 1, 7, 9 ] "# ), RocList::from_slice(&[3]), RocList ); } #[test] fn gen_wrap_first() { assert_evals_to!( indoc!( r#" wrapFirst = \list -> [ List.first list ] wrapFirst [ 1, 2 ] "# ), // RocList::from_slice(&[1]), // RocList &[1], &'static [i64] ); } #[test] fn gen_duplicate() { assert_evals_to!( indoc!( r#" # Duplicate the first element into the second index dupe = \list -> when List.first list is Ok elem -> List.set list 1 elem _ -> [] dupe [ 1, 2 ] "# ), RocList::from_slice(&[1, 1]), RocList ); } #[test] fn gen_swap() { assert_evals_to!( indoc!( r#" app "quicksort" provides [ main ] to "./platform" swap : Nat, Nat, List a -> List a swap = \i, j, list -> when Pair (List.get list i) (List.get list j) is Pair (Ok atI) (Ok atJ) -> list |> List.set i atJ |> List.set j atI _ -> [] main = swap 0 1 [ 1, 2 ] "# ), RocList::from_slice(&[2, 1]), RocList ); } // #[test] // fn gen_partition() { // assert_evals_to!( // indoc!( // r#" // swap : I64, I64, List a -> List a // swap = \i, j, list -> // when Pair (List.get list i) (List.get list j) is // Pair (Ok atI) (Ok atJ) -> // list // |> List.set i atJ // |> List.set j atI // // _ -> // [] // partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] // partition = \low, high, initialList -> // when List.get initialList high is // Ok pivot -> // when partitionHelp (low - 1) low initialList high pivot is // Pair newI newList -> // Pair (newI + 1) (swap (newI + 1) high newList) // // Err _ -> // Pair (low - 1) initialList // // // partitionHelp : I64, I64, List (Num a), I64, I64 -> [ Pair I64 (List (Num a)) ] // partitionHelp = \i, j, list, high, pivot -> // if j < high then // when List.get list j is // Ok value -> // if value <= pivot then // partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot // else // partitionHelp i (j + 1) list high pivot // // Err _ -> // Pair i list // else // Pair i list // // # when partition 0 0 [ 1,2,3,4,5 ] is // # Pair list _ -> list // [ 1,3 ] // "# // ), // RocList::from_slice(&[2, 1]), // RocList // ); // } // #[test] // fn gen_partition() { // assert_evals_to!( // indoc!( // r#" // swap : I64, I64, List a -> List a // swap = \i, j, list -> // when Pair (List.get list i) (List.get list j) is // Pair (Ok atI) (Ok atJ) -> // list // |> List.set i atJ // |> List.set j atI // // _ -> // [] // partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] // partition = \low, high, initialList -> // when List.get initialList high is // Ok pivot -> // when partitionHelp (low - 1) low initialList high pivot is // Pair newI newList -> // Pair (newI + 1) (swap (newI + 1) high newList) // // Err _ -> // Pair (low - 1) initialList // // // partitionHelp : I64, I64, List (Num a), I64, I64 -> [ Pair I64 (List (Num a)) ] // // # when partition 0 0 [ 1,2,3,4,5 ] is // # Pair list _ -> list // [ 1,3 ] // "# // ), // RocList::from_slice(&[2, 1]), // RocList // ); // } #[test] fn gen_quicksort() { with_larger_debug_stack(|| { assert_evals_to!( indoc!( r#" quicksort : List (Num a) -> List (Num a) quicksort = \list -> n = List.len list quicksortHelp list 0 (n - 1) quicksortHelp : List (Num a), Nat, Nat -> List (Num a) quicksortHelp = \list, low, high -> if low < high then when partition low high list is Pair partitionIndex partitioned -> partitioned |> quicksortHelp low (partitionIndex - 1) |> quicksortHelp (partitionIndex + 1) high else list swap : Nat, Nat, List a -> List a swap = \i, j, list -> when Pair (List.get list i) (List.get list j) is Pair (Ok atI) (Ok atJ) -> list |> List.set i atJ |> List.set j atI _ -> [] partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ] partition = \low, high, initialList -> when List.get initialList high is Ok pivot -> when partitionHelp (low - 1) low initialList high pivot is Pair newI newList -> Pair (newI + 1) (swap (newI + 1) high newList) Err _ -> Pair (low - 1) initialList partitionHelp : Nat, Nat, List (Num a), Nat, (Num a) -> [ Pair Nat (List (Num a)) ] partitionHelp = \i, j, list, high, pivot -> if j < high then when List.get list j is Ok value -> if value <= pivot then partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot else partitionHelp i (j + 1) list high pivot Err _ -> Pair i list else Pair i list quicksort [ 7, 4, 21, 19 ] "# ), RocList::from_slice(&[4, 7, 19, 21]), RocList ); }) } #[test] fn foobar2() { with_larger_debug_stack(|| { assert_evals_to!( indoc!( r#" quicksort : List (Num a) -> List (Num a) quicksort = \list -> quicksortHelp list 0 (List.len list - 1) quicksortHelp : List (Num a), Nat, Nat -> List (Num a) quicksortHelp = \list, low, high -> if low < high then when partition low high list is Pair partitionIndex partitioned -> partitioned |> quicksortHelp low (partitionIndex - 1) |> quicksortHelp (partitionIndex + 1) high else list swap : Nat, Nat, List a -> List a swap = \i, j, list -> when Pair (List.get list i) (List.get list j) is Pair (Ok atI) (Ok atJ) -> list |> List.set i atJ |> List.set j atI _ -> [] partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ] partition = \low, high, initialList -> when List.get initialList high is Ok pivot -> when partitionHelp (low - 1) low initialList high pivot is Pair newI newList -> Pair (newI + 1) (swap (newI + 1) high newList) Err _ -> Pair (low - 1) initialList partitionHelp : Nat, Nat, List (Num a), Nat, Num a -> [ Pair Nat (List (Num a)) ] partitionHelp = \i, j, list, high, pivot -> # if j < high then if False then when List.get list j is Ok value -> if value <= pivot then partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot else partitionHelp i (j + 1) list high pivot Err _ -> Pair i list else Pair i list quicksort [ 7, 4, 21, 19 ] "# ), RocList::from_slice(&[19, 7, 4, 21]), RocList ); }) } #[test] fn foobar() { with_larger_debug_stack(|| { assert_evals_to!( indoc!( r#" quicksort : List (Num a) -> List (Num a) quicksort = \list -> quicksortHelp list 0 (List.len list - 1) quicksortHelp : List (Num a), Nat, Nat -> List (Num a) quicksortHelp = \list, low, high -> if low < high then when partition low high list is Pair partitionIndex partitioned -> partitioned |> quicksortHelp low (partitionIndex - 1) |> quicksortHelp (partitionIndex + 1) high else list swap : Nat, Nat, List a -> List a swap = \i, j, list -> when Pair (List.get list i) (List.get list j) is Pair (Ok atI) (Ok atJ) -> list |> List.set i atJ |> List.set j atI _ -> [] partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ] partition = \low, high, initialList -> when List.get initialList high is Ok pivot -> when partitionHelp (low - 1) low initialList high pivot is Pair newI newList -> Pair (newI + 1) (swap (newI + 1) high newList) Err _ -> Pair (low - 1) initialList partitionHelp : Nat, Nat, List (Num a), Nat, Num a -> [ Pair Nat (List (Num a)) ] partitionHelp = \i, j, list, high, pivot -> if j < high then when List.get list j is Ok value -> if value <= pivot then partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot else partitionHelp i (j + 1) list high pivot Err _ -> Pair i list else Pair i list when List.first (quicksort [0x1]) is _ -> 4 "# ), 4, i64 ); }) } #[test] fn empty_list_increment_decrement() { assert_evals_to!( indoc!( r#" x : List I64 x = [] List.len x + List.len x "# ), 0, i64 ); } #[test] fn list_literal_increment_decrement() { assert_evals_to!( indoc!( r#" x : List I64 x = [1,2,3] List.len x + List.len x "# ), 6, i64 ); } #[test] fn list_pass_to_function() { assert_evals_to!( indoc!( r#" x : List I64 x = [1,2,3] id : List I64 -> List I64 id = \y -> y id x "# ), RocList::from_slice(&[1, 2, 3]), RocList ); } #[test] fn list_pass_to_set() { assert_evals_to!( indoc!( r#" x : List I64 x = [1,2,3] id : List I64 -> List I64 id = \y -> List.set y 0 0 id x "# ), RocList::from_slice(&[0, 2, 3]), RocList ); } #[test] fn list_wrap_in_tag() { assert_evals_to!( indoc!( r#" id : List I64 -> [ Pair (List I64) I64 ] id = \y -> Pair y 4 when id [1,2,3] is Pair v _ -> v "# ), RocList::from_slice(&[1, 2, 3]), RocList ); } #[test] fn list_contains() { assert_evals_to!(indoc!("List.contains [1,2,3] 1"), true, bool); assert_evals_to!(indoc!("List.contains [1,2,3] 4"), false, bool); assert_evals_to!(indoc!("List.contains [] 4"), false, bool); } #[test] fn list_sum() { assert_evals_to!("List.sum []", 0, i64); assert_evals_to!("List.sum [ 1, 2, 3 ]", 6, i64); assert_evals_to!("List.sum [ 1.1, 2.2, 3.3 ]", 6.6, f64); } #[test] fn list_keep_oks() { assert_evals_to!("List.keepOks [] (\\x -> x)", 0, i64); assert_evals_to!("List.keepOks [1,2] (\\x -> Ok x)", &[1, 2], &[i64]); assert_evals_to!("List.keepOks [1,2] (\\x -> x % 2)", &[1, 0], &[i64]); assert_evals_to!("List.keepOks [Ok 1, Err 2] (\\x -> x)", &[1], &[i64]); } #[test] fn list_keep_errs() { assert_evals_to!("List.keepErrs [] (\\x -> x)", 0, i64); assert_evals_to!("List.keepErrs [1,2] (\\x -> Err x)", &[1, 2], &[i64]); assert_evals_to!( "List.keepErrs [0,1,2] (\\x -> x % 0 |> Result.mapErr (\\_ -> 32))", &[32, 32, 32], &[i64] ); assert_evals_to!("List.keepErrs [Ok 1, Err 2] (\\x -> x)", &[2], &[i64]); } #[test] fn list_map_with_index() { assert_evals_to!( "List.mapWithIndex [0,0,0] (\\index, x -> index + x)", &[0, 1, 2], &[i64] ); } #[test] #[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)] fn cleanup_because_exception() { assert_evals_to!( indoc!( r#" x = [ 1,2 ] 5 + Num.maxInt + 3 + List.len x "# ), RocList::from_slice(&[false; 1]), RocList ); } }