mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
inline fn swapHelp(width: usize, temporary: [*]u8, ptr1: [*]u8, ptr2: [*]u8) void {
|
||||
|
|
|
@ -49,6 +49,7 @@ comptime {
|
|||
exportListFn(list.listSet, "set");
|
||||
exportListFn(list.listSetInPlace, "set_in_place");
|
||||
exportListFn(list.listSwap, "swap");
|
||||
exportListFn(list.listAny, "any");
|
||||
}
|
||||
|
||||
// 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_SET: &str = "roc_builtins.list.set";
|
||||
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_EQ: &str = "roc_builtins.dec.eq";
|
||||
|
|
|
@ -1055,6 +1055,16 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
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
|
||||
add_top_level_function_type!(
|
||||
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_UNTIL => list_walk_until,
|
||||
LIST_SORT_WITH => list_sort_with,
|
||||
LIST_ANY => list_any,
|
||||
DICT_TEST_HASH => dict_hash_test_only,
|
||||
DICT_LEN => dict_len,
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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
|
||||
fn dict_hash_test_only(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
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_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_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,
|
||||
|
@ -4863,6 +4863,30 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
_ => 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 } => {
|
||||
let (dict, dict_layout) = load_symbol_and_layout(scope, &xs);
|
||||
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
|
||||
| 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>(
|
||||
builder: &Builder<'ctx>,
|
||||
ctx: &'ctx Context,
|
||||
|
|
|
@ -45,6 +45,7 @@ pub enum LowLevel {
|
|||
ListDrop,
|
||||
ListDropAt,
|
||||
ListSwap,
|
||||
ListAny,
|
||||
DictSize,
|
||||
DictEmpty,
|
||||
DictInsert,
|
||||
|
@ -221,6 +222,7 @@ macro_rules! higher_order {
|
|||
| ListKeepOks
|
||||
| ListKeepErrs
|
||||
| ListSortWith
|
||||
| ListAny
|
||||
| DictWalk
|
||||
};
|
||||
}
|
||||
|
@ -254,6 +256,7 @@ impl LowLevel {
|
|||
ListKeepOks => 1,
|
||||
ListKeepErrs => 1,
|
||||
ListSortWith => 1,
|
||||
ListAny => 1,
|
||||
DictWalk => 2,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1064,6 +1064,7 @@ define_builtins! {
|
|||
41 LIST_DROP_FIRST: "dropFirst"
|
||||
42 LIST_JOIN_MAP: "joinMap"
|
||||
43 LIST_JOIN_MAP_CONCAT: "#joinMapConcat"
|
||||
44 LIST_ANY: "any"
|
||||
}
|
||||
5 RESULT: "Result" => {
|
||||
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)
|
||||
}
|
||||
|
||||
ListKeepIf { 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_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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -617,7 +617,8 @@ impl<'a> BorrowInfState<'a> {
|
|||
ListMap { xs }
|
||||
| ListKeepIf { xs }
|
||||
| ListKeepOks { xs }
|
||||
| ListKeepErrs { xs } => {
|
||||
| ListKeepErrs { xs }
|
||||
| ListAny { xs } => {
|
||||
// own the list if the function wants to own the element
|
||||
if !function_ps[0].borrow {
|
||||
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]),
|
||||
ListMap3 => arena.alloc_slice_copy(&[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])
|
||||
}
|
||||
ListContains => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
|
|
|
@ -530,7 +530,8 @@ impl<'a> Context<'a> {
|
|||
ListMap { xs }
|
||||
| ListKeepIf { xs }
|
||||
| ListKeepOks { xs }
|
||||
| ListKeepErrs { xs } => {
|
||||
| ListKeepErrs { xs }
|
||||
| ListAny { xs } => {
|
||||
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
|
||||
|
||||
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];
|
||||
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 => {
|
||||
debug_assert_eq!(arg_symbols.len(), 2);
|
||||
let xs = arg_symbols[0];
|
||||
|
|
|
@ -47,6 +47,9 @@ pub enum HigherOrder {
|
|||
ListSortWith {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListAny {
|
||||
xs: Symbol,
|
||||
},
|
||||
DictWalk {
|
||||
xs: Symbol,
|
||||
state: Symbol,
|
||||
|
@ -69,6 +72,7 @@ impl HigherOrder {
|
|||
HigherOrder::ListKeepErrs { .. } => 1,
|
||||
HigherOrder::ListSortWith { .. } => 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]
|
||||
#[should_panic(expected = r#"Roc failed with message: "invalid ret_layout""#)]
|
||||
fn lists_with_incompatible_type_param_in_if() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue