Merge branch 'trunk' into morphic-lib

This commit is contained in:
Richard Feldman 2021-05-22 15:21:50 -04:00 committed by GitHub
commit c5da16f071
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 129 additions and 6 deletions

View file

@ -665,6 +665,42 @@ pub fn listAppend(list: RocList, alignment: usize, element: Opaque, element_widt
return output; return output;
} }
pub fn listDrop(
list: RocList,
alignment: usize,
element_width: usize,
drop_count: usize,
dec: Dec,
) callconv(.C) RocList {
if (list.bytes) |source_ptr| {
const size = list.len();
const keep_count = size - drop_count;
var i: usize = 0;
const iterations = std.math.min(drop_count, size);
while (i < iterations) : (i += 1) {
const element = source_ptr + i * element_width;
dec(element);
}
if (drop_count >= size) {
return RocList.empty();
}
const output = RocList.allocate(std.heap.c_allocator, alignment, keep_count, element_width);
const target_ptr = output.bytes orelse unreachable;
@memcpy(target_ptr, source_ptr + drop_count * element_width, keep_count * element_width);
utils.decref(std.heap.c_allocator, alignment, list.bytes, size * element_width);
return output;
} else {
return RocList.empty();
}
}
pub fn listRange(width: utils.IntWidth, low: Opaque, high: Opaque) callconv(.C) RocList { pub fn listRange(width: utils.IntWidth, low: Opaque, high: Opaque) callconv(.C) RocList {
const allocator = std.heap.c_allocator; const allocator = std.heap.c_allocator;
const IntWidth = utils.IntWidth; const IntWidth = utils.IntWidth;

View file

@ -25,6 +25,7 @@ comptime {
exportListFn(list.listReverse, "reverse"); exportListFn(list.listReverse, "reverse");
exportListFn(list.listSortWith, "sort_with"); exportListFn(list.listSortWith, "sort_with");
exportListFn(list.listConcat, "concat"); exportListFn(list.listConcat, "concat");
exportListFn(list.listDrop, "drop");
} }
// Dict Module // Dict Module

View file

@ -76,6 +76,7 @@ pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains"; pub const LIST_CONTAINS: &str = "roc_builtins.list.contains";
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat"; pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
pub const LIST_APPEND: &str = "roc_builtins.list.append"; pub const LIST_APPEND: &str = "roc_builtins.list.append";
pub const LIST_DROP: &str = "roc_builtins.list.drop";
pub const LIST_SINGLE: &str = "roc_builtins.list.single"; pub const LIST_SINGLE: &str = "roc_builtins.list.single";
pub const LIST_JOIN: &str = "roc_builtins.list.join"; pub const LIST_JOIN: &str = "roc_builtins.list.join";
pub const LIST_RANGE: &str = "roc_builtins.list.range"; pub const LIST_RANGE: &str = "roc_builtins.list.range";

View file

@ -848,6 +848,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(list_type(flex(TVAR1))), Box::new(list_type(flex(TVAR1))),
); );
// drop : List elem, Nat -> List elem
add_top_level_function_type!(
Symbol::LIST_DROP,
vec![list_type(flex(TVAR1)), nat_type()],
Box::new(list_type(flex(TVAR1))),
);
// prepend : List elem, elem -> List elem // prepend : List elem, elem -> List elem
add_top_level_function_type!( add_top_level_function_type!(
Symbol::LIST_PREPEND, Symbol::LIST_PREPEND,

View file

@ -84,6 +84,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
LIST_MAP => list_map, LIST_MAP => list_map,
LIST_MAP2 => list_map2, LIST_MAP2 => list_map2,
LIST_MAP3 => list_map3, LIST_MAP3 => list_map3,
LIST_DROP => list_drop,
LIST_MAP_WITH_INDEX => list_map_with_index, LIST_MAP_WITH_INDEX => list_map_with_index,
LIST_KEEP_IF => list_keep_if, LIST_KEEP_IF => list_keep_if,
LIST_KEEP_OKS => list_keep_oks, LIST_KEEP_OKS => list_keep_oks,
@ -1881,6 +1882,28 @@ fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
list_ret_var, list_ret_var,
) )
} }
/// List.drop : List elem, Nat -> List elem
fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let index_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::ListDrop,
args: vec![
(list_var, Var(Symbol::ARG_1)),
(index_var, Var(Symbol::ARG_2)),
],
ret_var: list_var,
};
defn(
symbol,
vec![(list_var, Symbol::ARG_1), (index_var, Symbol::ARG_2)],
var_store,
body,
list_var,
)
}
/// List.append : List elem, elem -> List elem /// List.append : List elem, elem -> List elem
fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def { fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def {

View file

@ -6,9 +6,9 @@ use crate::llvm::build_dict::{
use crate::llvm::build_hash::generic_hash; use crate::llvm::build_hash::generic_hash;
use crate::llvm::build_list::{ use crate::llvm::build_list::{
allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat, list_contains, allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat, list_contains,
list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, list_drop, list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len,
list_map2, list_map3, list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, list_map, list_map2, list_map3, list_map_with_index, list_prepend, list_range, list_repeat,
list_set, list_single, list_sort_with, list_walk_help, list_reverse, list_set, list_single, list_sort_with, list_walk_help,
}; };
use crate::llvm::build_str::{ use crate::llvm::build_str::{
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
@ -3883,6 +3883,27 @@ fn run_low_level<'a, 'ctx, 'env>(
list_append(env, inplace, original_wrapper, elem, elem_layout) list_append(env, inplace, original_wrapper, elem, elem_layout)
} }
ListDrop => {
// List.drop : List elem, Nat -> List elem
debug_assert_eq!(args.len(), 2);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let original_wrapper = list.into_struct_value();
let count = load_symbol(scope, &args[1]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(_, element_layout)) => list_drop(
env,
layout_ids,
original_wrapper,
count.into_int_value(),
element_layout,
),
_ => unreachable!("Invalid layout {:?} in List.drop", list_layout),
}
}
ListPrepend => { ListPrepend => {
// List.prepend : List elem, elem -> List elem // List.prepend : List elem, elem -> List elem
debug_assert_eq!(args.len(), 2); debug_assert_eq!(args.len(), 2);

View file

@ -322,6 +322,28 @@ pub fn list_append<'a, 'ctx, 'env>(
) )
} }
/// List.drop : List elem, Nat -> List elem
pub fn list_drop<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
original_wrapper: StructValue<'ctx>,
count: IntValue<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let dec_element_fn = build_dec_wrapper(env, layout_ids, &element_layout);
call_bitcode_fn_returns_list(
env,
&[
pass_list_as_i128(env, original_wrapper.into()),
alignment_intvalue(env, &element_layout),
layout_width(env, &element_layout),
count.into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
&bitcode::LIST_DROP,
)
}
/// List.set : List elem, Int, elem -> List elem /// List.set : List elem, Int, elem -> List elem
pub fn list_set<'a, 'ctx, 'env>( pub fn list_set<'a, 'ctx, 'env>(
parent: FunctionValue<'ctx>, parent: FunctionValue<'ctx>,

View file

@ -128,9 +128,7 @@ mod gen_num {
af = 31 af = 31
ag = 32 ag = 32
# This can't be one line because it causes a stack overflow in the frontend :( a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z + aa + ab + ac + ad + ae + af + ag
tmp = a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q
tmp + r + s + t + u + v + w + x + y + z + aa + ab + ac + ad + ae + af + ag
"# "#
), ),
528, 528,

View file

@ -39,6 +39,7 @@ pub enum LowLevel {
ListKeepOks, ListKeepOks,
ListKeepErrs, ListKeepErrs,
ListSortWith, ListSortWith,
ListDrop,
DictSize, DictSize,
DictEmpty, DictEmpty,
DictInsert, DictInsert,

View file

@ -928,6 +928,7 @@ define_builtins! {
29 LIST_WALK_UNTIL: "walkUntil" 29 LIST_WALK_UNTIL: "walkUntil"
30 LIST_RANGE: "range" 30 LIST_RANGE: "range"
31 LIST_SORT_WITH: "sortWith" 31 LIST_SORT_WITH: "sortWith"
32 LIST_DROP: "drop"
} }
5 RESULT: "Result" => { 5 RESULT: "Result" => {
0 RESULT_RESULT: "Result" imported // the Result.Result type alias 0 RESULT_RESULT: "Result" imported // the Result.Result type alias

View file

@ -665,6 +665,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
// TODO when we have lists with capacity (if ever) // TODO when we have lists with capacity (if ever)
// List.append should own its first argument // List.append should own its first argument
ListAppend => arena.alloc_slice_copy(&[owned, owned]), ListAppend => arena.alloc_slice_copy(&[owned, owned]),
ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]),
Eq | NotEq => arena.alloc_slice_copy(&[borrowed, borrowed]), Eq | NotEq => arena.alloc_slice_copy(&[borrowed, borrowed]),

View file

@ -147,6 +147,17 @@ fn list_append() {
); );
} }
#[test]
fn list_drop() {
assert_evals_to!(
"List.drop [1,2,3] 2",
RocList::from_slice(&[3]),
RocList<i64>
);
assert_evals_to!("List.drop [] 1", RocList::from_slice(&[]), RocList<i64>);
assert_evals_to!("List.drop [1,2] 5", RocList::from_slice(&[]), RocList<i64>);
}
#[test] #[test]
fn list_append_to_empty_list() { fn list_append_to_empty_list() {
assert_evals_to!("List.append [] 3", RocList::from_slice(&[3]), RocList<i64>); assert_evals_to!("List.append [] 3", RocList::from_slice(&[3]), RocList<i64>);