mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
670 lines
17 KiB
Rust
670 lines
17 KiB
Rust
#[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::{can_expr, infer_expr, uniq_expr, with_larger_debug_stack, CanExprOut};
|
|
use bumpalo::Bump;
|
|
use inkwell::context::Context;
|
|
use inkwell::execution_engine::JitFunction;
|
|
use inkwell::passes::PassManager;
|
|
use inkwell::types::BasicType;
|
|
use inkwell::OptimizationLevel;
|
|
use roc_collections::all::ImMap;
|
|
use roc_gen::llvm::build::{build_proc, build_proc_header};
|
|
use roc_gen::llvm::convert::basic_type_from_layout;
|
|
use roc_mono::expr::{Expr, Procs};
|
|
use roc_mono::layout::Layout;
|
|
use roc_types::subs::Subs;
|
|
|
|
#[test]
|
|
fn empty_list_literal() {
|
|
assert_evals_to!("[]", &[], &'static [i64]);
|
|
}
|
|
|
|
#[test]
|
|
fn int_list_literal() {
|
|
assert_evals_to!("[ 12, 9, 6, 3 ]", &[12, 9, 6, 3], &'static [i64]);
|
|
}
|
|
|
|
#[test]
|
|
fn list_push() {
|
|
assert_evals_to!("List.push [1] 2", &[1, 2], &'static [i64]);
|
|
assert_evals_to!("List.push [1, 1] 2", &[1, 1, 2], &'static [i64]);
|
|
assert_evals_to!("List.push [] 3", &[3], &'static [i64]);
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
initThrees : List Int
|
|
initThrees =
|
|
[]
|
|
|
|
List.push (List.push initThrees 3) 3
|
|
"#
|
|
),
|
|
&[3, 3],
|
|
&'static [i64]
|
|
);
|
|
assert_evals_to!(
|
|
"List.push [ True, False ] True",
|
|
&[true, false, true],
|
|
&'static [bool]
|
|
);
|
|
assert_evals_to!(
|
|
"List.push [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ] 23",
|
|
&[11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_single() {
|
|
assert_evals_to!("List.single 1", &[1], &'static [i64]);
|
|
assert_evals_to!("List.single 5.6", &[5.6], &'static [f64]);
|
|
}
|
|
|
|
#[test]
|
|
fn list_repeat() {
|
|
assert_evals_to!("List.repeat 5 1", &[1, 1, 1, 1, 1], &'static [i64]);
|
|
assert_evals_to!("List.repeat 4 2", &[2, 2, 2, 2], &'static [i64]);
|
|
|
|
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",
|
|
&[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_reverse() {
|
|
assert_evals_to!(
|
|
"List.reverse [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]",
|
|
&[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
|
|
&'static [i64]
|
|
);
|
|
assert_evals_to!("List.reverse [1, 2, 3]", &[3, 2, 1], &'static [i64]);
|
|
assert_evals_to!("List.reverse [4]", &[4], &'static [i64]);
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
emptyList : List Int
|
|
emptyList =
|
|
[]
|
|
|
|
List.reverse emptyList
|
|
"#
|
|
),
|
|
&[],
|
|
&'static [i64]
|
|
);
|
|
assert_evals_to!("List.reverse []", &[], &'static [i64]);
|
|
}
|
|
|
|
#[test]
|
|
fn list_append() {
|
|
assert_evals_to!("List.append [] []", &[], &'static [i64]);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
firstList : List Int
|
|
firstList =
|
|
[]
|
|
|
|
secondList : List Int
|
|
secondList =
|
|
[]
|
|
|
|
List.append firstList secondList
|
|
"#
|
|
),
|
|
&[],
|
|
&'static [i64]
|
|
);
|
|
|
|
assert_evals_to!("List.append [ 12, 13 ] []", &[12, 13], &'static [i64]);
|
|
assert_evals_to!(
|
|
"List.append [ 34, 43 ] [ 64, 55, 66 ]",
|
|
&[34, 43, 64, 55, 66],
|
|
&'static [i64]
|
|
);
|
|
|
|
assert_evals_to!("List.append [] [ 23, 24 ]", &[23, 24], &'static [i64]);
|
|
|
|
assert_evals_to!(
|
|
"List.append [ 1, 2 ] [ 3, 4 ]",
|
|
&[1, 2, 3, 4],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
fn assert_append_worked(num_elems1: i64, num_elems2: i64) {
|
|
let vec1: Vec<i64> = (0..num_elems1)
|
|
.map(|i| 12345 % (i + num_elems1 + num_elems2 + 1))
|
|
.collect();
|
|
let vec2: Vec<i64> = (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);
|
|
|
|
let expected_slice: &[i64] = expected.as_ref();
|
|
|
|
assert_evals_to!(
|
|
&format!("List.append {} {}", slice_str1, slice_str2),
|
|
expected_slice,
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_append_empty_list() {
|
|
assert_append_worked(0, 0);
|
|
assert_append_worked(1, 0);
|
|
assert_append_worked(2, 0);
|
|
assert_append_worked(3, 0);
|
|
assert_append_worked(4, 0);
|
|
assert_append_worked(7, 0);
|
|
assert_append_worked(8, 0);
|
|
assert_append_worked(9, 0);
|
|
assert_append_worked(25, 0);
|
|
assert_append_worked(150, 0);
|
|
assert_append_worked(0, 1);
|
|
assert_append_worked(0, 2);
|
|
assert_append_worked(0, 3);
|
|
assert_append_worked(0, 4);
|
|
assert_append_worked(0, 7);
|
|
assert_append_worked(0, 8);
|
|
assert_append_worked(0, 9);
|
|
assert_append_worked(0, 25);
|
|
assert_append_worked(0, 150);
|
|
}
|
|
|
|
#[test]
|
|
fn list_append_nonempty_lists() {
|
|
assert_append_worked(1, 1);
|
|
assert_append_worked(1, 2);
|
|
assert_append_worked(1, 3);
|
|
assert_append_worked(2, 3);
|
|
assert_append_worked(2, 1);
|
|
assert_append_worked(2, 2);
|
|
assert_append_worked(3, 1);
|
|
assert_append_worked(3, 2);
|
|
assert_append_worked(2, 3);
|
|
assert_append_worked(3, 3);
|
|
assert_append_worked(4, 4);
|
|
assert_append_worked(150, 150);
|
|
assert_append_worked(129, 350);
|
|
assert_append_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]
|
|
fn first_wildcard_empty_list() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when List.first [] is
|
|
Ok _ -> 5
|
|
Err _ -> -1
|
|
"#
|
|
),
|
|
-1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
// TODO getting this to work requires generating a runtime error for the Ok
|
|
// branch here, which is not yet something we support as of when this
|
|
// test was originally written.
|
|
//
|
|
// #[test]
|
|
// fn first_empty_list() {
|
|
// assert_evals_to!(
|
|
// indoc!(
|
|
// r#"
|
|
// when List.first [] 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]
|
|
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",
|
|
&[12, 9, 33, 1, 5],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn set_unique_list_oob() {
|
|
assert_evals_to!(
|
|
"List.set [ 3, 17, 4.1 ] 1337 9.25",
|
|
&[3.0, 17.0, 4.1],
|
|
&'static [f64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn set_shared_int_list() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
shared = [ 2.1, 4.3 ]
|
|
|
|
# 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 }
|
|
"#
|
|
),
|
|
(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 ]
|
|
"#
|
|
),
|
|
&[3],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn gen_wrap_first() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
wrapFirst = \list ->
|
|
[ List.first list ]
|
|
|
|
wrapFirst [ 1, 2 ]
|
|
"#
|
|
),
|
|
&[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 ]
|
|
"#
|
|
),
|
|
&[1, 1],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn gen_quicksort() {
|
|
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), Int, Int -> 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 : Int, Int, 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 : Int, Int, List (Num a) -> [ Pair Int (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 : Int, Int, List (Num a), Int, Int -> [ Pair Int (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 ]
|
|
"#
|
|
),
|
|
&[4, 7, 19, 21],
|
|
&'static [i64]
|
|
);
|
|
})
|
|
}
|
|
|
|
#[test]
|
|
fn empty_list_increment_decrement() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : List Int
|
|
x = []
|
|
|
|
List.len x + List.len x
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_literal_increment_decrement() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : List Int
|
|
x = [1,2,3]
|
|
|
|
List.len x + List.len x
|
|
"#
|
|
),
|
|
6,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_pass_to_function() {
|
|
// yes
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : List Int
|
|
x = [1,2,3]
|
|
|
|
id : List Int -> List Int
|
|
id = \y -> y
|
|
|
|
id x
|
|
"#
|
|
),
|
|
&[1, 2, 3],
|
|
&'static [i64]
|
|
);
|
|
}
|
|
}
|