mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Implement List.any
This commit is contained in:
parent
0e500ba33c
commit
44938a9e35
15 changed files with 137 additions and 6 deletions
|
@ -1078,6 +1078,33 @@ pub fn listSortWith(
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn listAny(
|
||||||
|
list: RocList,
|
||||||
|
caller: Caller1,
|
||||||
|
data: Opaque,
|
||||||
|
inc_n_data: IncN,
|
||||||
|
data_is_owned: bool,
|
||||||
|
alignment: u32,
|
||||||
|
element_width: usize,
|
||||||
|
) callconv(.C) bool {
|
||||||
|
if (list.bytes) |source_ptr| {
|
||||||
|
const size = list.len();
|
||||||
|
var i: usize = 0;
|
||||||
|
var satisfied = false;
|
||||||
|
|
||||||
|
while (i < size) : (i += 1) {
|
||||||
|
const element = source_ptr + i * element_width;
|
||||||
|
caller(data, element, @ptrCast(?[*]u8, &satisfied));
|
||||||
|
|
||||||
|
if (satisfied) {
|
||||||
|
return satisfied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// SWAP ELEMENTS
|
// SWAP ELEMENTS
|
||||||
|
|
||||||
inline fn swapHelp(width: usize, temporary: [*]u8, ptr1: [*]u8, ptr2: [*]u8) void {
|
inline fn swapHelp(width: usize, temporary: [*]u8, ptr1: [*]u8, ptr2: [*]u8) void {
|
||||||
|
|
|
@ -49,6 +49,7 @@ comptime {
|
||||||
exportListFn(list.listSet, "set");
|
exportListFn(list.listSet, "set");
|
||||||
exportListFn(list.listSetInPlace, "set_in_place");
|
exportListFn(list.listSetInPlace, "set_in_place");
|
||||||
exportListFn(list.listSwap, "swap");
|
exportListFn(list.listSwap, "swap");
|
||||||
|
exportListFn(list.listAny, "any");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dict Module
|
// Dict Module
|
||||||
|
|
|
@ -188,6 +188,7 @@ pub const LIST_SORT_WITH: &str = "roc_builtins.list.sort_with";
|
||||||
pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
||||||
pub const LIST_SET: &str = "roc_builtins.list.set";
|
pub const LIST_SET: &str = "roc_builtins.list.set";
|
||||||
pub const LIST_SET_IN_PLACE: &str = "roc_builtins.list.set_in_place";
|
pub const LIST_SET_IN_PLACE: &str = "roc_builtins.list.set_in_place";
|
||||||
|
pub const LIST_ANY: &str = "roc_builtins.list.any";
|
||||||
|
|
||||||
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";
|
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";
|
||||||
pub const DEC_EQ: &str = "roc_builtins.dec.eq";
|
pub const DEC_EQ: &str = "roc_builtins.dec.eq";
|
||||||
|
|
|
@ -1055,6 +1055,16 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
Box::new(bool_type())
|
Box::new(bool_type())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// any: List elem, (elem -> Bool) -> Bool
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::LIST_ANY,
|
||||||
|
vec![
|
||||||
|
list_type(flex(TVAR1)),
|
||||||
|
closure(vec![flex(TVAR1)], TVAR2, Box::new(bool_type())),
|
||||||
|
],
|
||||||
|
Box::new(bool_type()),
|
||||||
|
);
|
||||||
|
|
||||||
// sortWith : List a, (a, a -> Ordering) -> List a
|
// sortWith : List a, (a, a -> Ordering) -> List a
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::LIST_SORT_WITH,
|
Symbol::LIST_SORT_WITH,
|
||||||
|
|
|
@ -105,6 +105,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
LIST_WALK_BACKWARDS => list_walk_backwards,
|
LIST_WALK_BACKWARDS => list_walk_backwards,
|
||||||
LIST_WALK_UNTIL => list_walk_until,
|
LIST_WALK_UNTIL => list_walk_until,
|
||||||
LIST_SORT_WITH => list_sort_with,
|
LIST_SORT_WITH => list_sort_with,
|
||||||
|
LIST_ANY => list_any,
|
||||||
DICT_TEST_HASH => dict_hash_test_only,
|
DICT_TEST_HASH => dict_hash_test_only,
|
||||||
DICT_LEN => dict_len,
|
DICT_LEN => dict_len,
|
||||||
DICT_EMPTY => dict_empty,
|
DICT_EMPTY => dict_empty,
|
||||||
|
@ -2695,6 +2696,11 @@ fn list_sort_with(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_2(symbol, LowLevel::ListSortWith, var_store)
|
lowlevel_2(symbol, LowLevel::ListSortWith, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List.any: List elem, (elem -> Bool) -> Bool
|
||||||
|
fn list_any(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::ListAny, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
/// Dict.hashTestOnly : k, v -> Nat
|
/// Dict.hashTestOnly : k, v -> Nat
|
||||||
fn dict_hash_test_only(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn dict_hash_test_only(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_2(symbol, LowLevel::Hash, var_store)
|
lowlevel_2(symbol, LowLevel::Hash, var_store)
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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::{
|
||||||
self, allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat,
|
self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_append, list_concat,
|
||||||
list_contains, list_drop, list_drop_at, list_get_unsafe, list_join, list_keep_errs,
|
list_contains, list_drop, list_drop_at, list_get_unsafe, list_join, list_keep_errs,
|
||||||
list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4,
|
list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4,
|
||||||
list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, list_set,
|
list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, list_set,
|
||||||
|
@ -4863,6 +4863,30 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
_ => unreachable!("invalid list layout"),
|
_ => unreachable!("invalid list layout"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ListAny { xs } => {
|
||||||
|
let (list, list_layout) = load_symbol_and_layout(scope, &xs);
|
||||||
|
let (function, closure, closure_layout) = function_details!();
|
||||||
|
|
||||||
|
match list_layout {
|
||||||
|
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||||
|
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||||
|
let argument_layouts = &[**element_layout];
|
||||||
|
|
||||||
|
let roc_function_call = roc_function_call(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
function,
|
||||||
|
closure,
|
||||||
|
closure_layout,
|
||||||
|
function_owns_closure_data,
|
||||||
|
argument_layouts,
|
||||||
|
);
|
||||||
|
|
||||||
|
list_any(env, roc_function_call, list, element_layout)
|
||||||
|
}
|
||||||
|
_ => unreachable!("invalid list layout"),
|
||||||
|
}
|
||||||
|
}
|
||||||
DictWalk { xs, state } => {
|
DictWalk { xs, state } => {
|
||||||
let (dict, dict_layout) = load_symbol_and_layout(scope, &xs);
|
let (dict, dict_layout) = load_symbol_and_layout(scope, &xs);
|
||||||
let (default, default_layout) = load_symbol_and_layout(scope, &state);
|
let (default, default_layout) = load_symbol_and_layout(scope, &state);
|
||||||
|
@ -5713,7 +5737,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk
|
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk
|
||||||
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
|
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
|
||||||
| DictWalk => unreachable!("these are higher order, and are handled elsewhere"),
|
| ListAny | DictWalk => unreachable!("these are higher order, and are handled elsewhere"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -896,6 +896,28 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List.any : List elem, \(elem -> Bool) -> Bool
|
||||||
|
pub fn list_any<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
roc_function_call: RocFunctionCall<'ctx>,
|
||||||
|
list: BasicValueEnum<'ctx>,
|
||||||
|
element_layout: &Layout<'a>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
call_bitcode_fn(
|
||||||
|
env,
|
||||||
|
&[
|
||||||
|
pass_list_cc(env, list),
|
||||||
|
roc_function_call.caller.into(),
|
||||||
|
pass_as_opaque(env, roc_function_call.data),
|
||||||
|
roc_function_call.inc_n_data.into(),
|
||||||
|
roc_function_call.data_is_owned.into(),
|
||||||
|
env.alignment_intvalue(element_layout),
|
||||||
|
layout_width(env, element_layout),
|
||||||
|
],
|
||||||
|
bitcode::LIST_ANY,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decrementing_elem_loop<'ctx, LoopFn>(
|
pub fn decrementing_elem_loop<'ctx, LoopFn>(
|
||||||
builder: &Builder<'ctx>,
|
builder: &Builder<'ctx>,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
|
|
|
@ -45,6 +45,7 @@ pub enum LowLevel {
|
||||||
ListDrop,
|
ListDrop,
|
||||||
ListDropAt,
|
ListDropAt,
|
||||||
ListSwap,
|
ListSwap,
|
||||||
|
ListAny,
|
||||||
DictSize,
|
DictSize,
|
||||||
DictEmpty,
|
DictEmpty,
|
||||||
DictInsert,
|
DictInsert,
|
||||||
|
@ -221,6 +222,7 @@ macro_rules! higher_order {
|
||||||
| ListKeepOks
|
| ListKeepOks
|
||||||
| ListKeepErrs
|
| ListKeepErrs
|
||||||
| ListSortWith
|
| ListSortWith
|
||||||
|
| ListAny
|
||||||
| DictWalk
|
| DictWalk
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -254,6 +256,7 @@ impl LowLevel {
|
||||||
ListKeepOks => 1,
|
ListKeepOks => 1,
|
||||||
ListKeepErrs => 1,
|
ListKeepErrs => 1,
|
||||||
ListSortWith => 1,
|
ListSortWith => 1,
|
||||||
|
ListAny => 1,
|
||||||
DictWalk => 2,
|
DictWalk => 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1064,6 +1064,7 @@ define_builtins! {
|
||||||
41 LIST_DROP_FIRST: "dropFirst"
|
41 LIST_DROP_FIRST: "dropFirst"
|
||||||
42 LIST_JOIN_MAP: "joinMap"
|
42 LIST_JOIN_MAP: "joinMap"
|
||||||
43 LIST_JOIN_MAP_CONCAT: "#joinMapConcat"
|
43 LIST_JOIN_MAP_CONCAT: "#joinMapConcat"
|
||||||
|
44 LIST_ANY: "any"
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|
|
@ -967,7 +967,6 @@ fn call_spec(
|
||||||
|
|
||||||
add_loop(builder, block, state_type, init_state, loop_body)
|
add_loop(builder, block, state_type, init_state, loop_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
ListKeepIf { xs } => {
|
ListKeepIf { xs } => {
|
||||||
let list = env.symbols[xs];
|
let list = env.symbols[xs];
|
||||||
|
|
||||||
|
@ -1073,6 +1072,25 @@ fn call_spec(
|
||||||
let state_layout = Layout::Builtin(Builtin::List(&output_element_layout));
|
let state_layout = Layout::Builtin(Builtin::List(&output_element_layout));
|
||||||
let state_type = layout_spec(builder, &state_layout)?;
|
let state_type = layout_spec(builder, &state_layout)?;
|
||||||
|
|
||||||
|
add_loop(builder, block, state_type, init_state, loop_body)
|
||||||
|
}
|
||||||
|
ListAny { xs } => {
|
||||||
|
let list = env.symbols[xs];
|
||||||
|
|
||||||
|
let loop_body = |builder: &mut FuncDefBuilder, block, _state| {
|
||||||
|
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||||
|
let element = builder.add_bag_get(block, bag)?;
|
||||||
|
|
||||||
|
let new_state = call_function!(builder, block, [element]);
|
||||||
|
|
||||||
|
Ok(new_state)
|
||||||
|
};
|
||||||
|
|
||||||
|
let state_layout = Layout::Builtin(Builtin::Int1);
|
||||||
|
let state_type = layout_spec(builder, &state_layout)?;
|
||||||
|
|
||||||
|
let init_state = new_num(builder, block)?;
|
||||||
|
|
||||||
add_loop(builder, block, state_type, init_state, loop_body)
|
add_loop(builder, block, state_type, init_state, loop_body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,7 +617,8 @@ impl<'a> BorrowInfState<'a> {
|
||||||
ListMap { xs }
|
ListMap { xs }
|
||||||
| ListKeepIf { xs }
|
| ListKeepIf { xs }
|
||||||
| ListKeepOks { xs }
|
| ListKeepOks { xs }
|
||||||
| ListKeepErrs { xs } => {
|
| ListKeepErrs { xs }
|
||||||
|
| ListAny { xs } => {
|
||||||
// own the list if the function wants to own the element
|
// own the list if the function wants to own the element
|
||||||
if !function_ps[0].borrow {
|
if !function_ps[0].borrow {
|
||||||
self.own_var(*xs);
|
self.own_var(*xs);
|
||||||
|
@ -949,7 +950,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
||||||
ListMap3 => arena.alloc_slice_copy(&[owned, owned, owned, function, closure_data]),
|
ListMap3 => arena.alloc_slice_copy(&[owned, owned, owned, function, closure_data]),
|
||||||
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
||||||
ListKeepIf | ListKeepOks | ListKeepErrs => {
|
ListKeepIf | ListKeepOks | ListKeepErrs | ListAny => {
|
||||||
arena.alloc_slice_copy(&[owned, function, closure_data])
|
arena.alloc_slice_copy(&[owned, function, closure_data])
|
||||||
}
|
}
|
||||||
ListContains => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
ListContains => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
|
|
|
@ -530,7 +530,8 @@ impl<'a> Context<'a> {
|
||||||
ListMap { xs }
|
ListMap { xs }
|
||||||
| ListKeepIf { xs }
|
| ListKeepIf { xs }
|
||||||
| ListKeepOks { xs }
|
| ListKeepOks { xs }
|
||||||
| ListKeepErrs { xs } => {
|
| ListKeepErrs { xs }
|
||||||
|
| ListAny { xs } => {
|
||||||
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
|
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
|
||||||
|
|
||||||
let b = self.add_dec_after_lowlevel(arguments, &borrows, b, b_live_vars);
|
let b = self.add_dec_after_lowlevel(arguments, &borrows, b, b_live_vars);
|
||||||
|
|
|
@ -4113,6 +4113,11 @@ pub fn with_hole<'a>(
|
||||||
let xs = arg_symbols[0];
|
let xs = arg_symbols[0];
|
||||||
match_on_closure_argument!(ListKeepIf, [xs])
|
match_on_closure_argument!(ListKeepIf, [xs])
|
||||||
}
|
}
|
||||||
|
ListAny => {
|
||||||
|
debug_assert_eq!(arg_symbols.len(), 2);
|
||||||
|
let xs = arg_symbols[0];
|
||||||
|
match_on_closure_argument!(ListAny, [xs])
|
||||||
|
}
|
||||||
ListKeepOks => {
|
ListKeepOks => {
|
||||||
debug_assert_eq!(arg_symbols.len(), 2);
|
debug_assert_eq!(arg_symbols.len(), 2);
|
||||||
let xs = arg_symbols[0];
|
let xs = arg_symbols[0];
|
||||||
|
|
|
@ -47,6 +47,9 @@ pub enum HigherOrder {
|
||||||
ListSortWith {
|
ListSortWith {
|
||||||
xs: Symbol,
|
xs: Symbol,
|
||||||
},
|
},
|
||||||
|
ListAny {
|
||||||
|
xs: Symbol,
|
||||||
|
},
|
||||||
DictWalk {
|
DictWalk {
|
||||||
xs: Symbol,
|
xs: Symbol,
|
||||||
state: Symbol,
|
state: Symbol,
|
||||||
|
@ -69,6 +72,7 @@ impl HigherOrder {
|
||||||
HigherOrder::ListKeepErrs { .. } => 1,
|
HigherOrder::ListKeepErrs { .. } => 1,
|
||||||
HigherOrder::ListSortWith { .. } => 2,
|
HigherOrder::ListSortWith { .. } => 2,
|
||||||
HigherOrder::DictWalk { .. } => 2,
|
HigherOrder::DictWalk { .. } => 2,
|
||||||
|
HigherOrder::ListAny { .. } => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2160,6 +2160,13 @@ fn list_sort_with() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_any() {
|
||||||
|
assert_evals_to!("List.any [] (\\e -> e > 3)", false, bool);
|
||||||
|
assert_evals_to!("List.any [ 1, 2, 3 ] (\\e -> e > 3)", false, bool);
|
||||||
|
assert_evals_to!("List.any [ 1, 2, 4 ] (\\e -> e > 3)", true, bool);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = r#"Roc failed with message: "invalid ret_layout""#)]
|
#[should_panic(expected = r#"Roc failed with message: "invalid ret_layout""#)]
|
||||||
fn lists_with_incompatible_type_param_in_if() {
|
fn lists_with_incompatible_type_param_in_if() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue