mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Implement List.find
`List.find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*` behaves as follows: ``` >>> List.find [1, 2, 3] (\n -> n > 2) Ok 2 >>> List.find [1, 2, 3] (\n -> n > 4) Err NotFound ``` We implement this as builtin in two phases. First, we call out to a pure-llvm-lowlevel `ListFindUnsafe` that returns a record indicating whether a satisfying element was found, and the value of that element (the value is all null bytes if the element wasn't found). Then, we lift that record to a `Result` via a standard construction of the can AST. Closes #1909
This commit is contained in:
parent
35df58c18f
commit
f65b174ab5
16 changed files with 417 additions and 8 deletions
|
@ -107,6 +107,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
LIST_WALK_UNTIL => list_walk_until,
|
||||
LIST_SORT_WITH => list_sort_with,
|
||||
LIST_ANY => list_any,
|
||||
LIST_FIND => list_find,
|
||||
DICT_TEST_HASH => dict_hash_test_only,
|
||||
DICT_LEN => dict_len,
|
||||
DICT_EMPTY => dict_empty,
|
||||
DICT_SINGLE => dict_single,
|
||||
|
@ -2724,6 +2726,92 @@ fn list_any(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
lowlevel_2(symbol, LowLevel::ListAny, var_store)
|
||||
}
|
||||
|
||||
/// List.find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*
|
||||
fn list_find(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list = Symbol::ARG_1;
|
||||
let find_predicate = Symbol::ARG_2;
|
||||
|
||||
let find_result = Symbol::LIST_FIND_RESULT;
|
||||
|
||||
let t_list = var_store.fresh();
|
||||
let t_pred_fn = var_store.fresh();
|
||||
let t_bool = var_store.fresh();
|
||||
let t_found = var_store.fresh();
|
||||
let t_value = var_store.fresh();
|
||||
let t_ret = var_store.fresh();
|
||||
let t_find_result = var_store.fresh();
|
||||
let t_ext_var1 = var_store.fresh();
|
||||
let t_ext_var2 = var_store.fresh();
|
||||
|
||||
// ListFindUnsafe returns { value: elem, found: Bool }.
|
||||
// When `found` is true, the value was found. Otherwise `List.find` should return `Err ...`
|
||||
let find_result_def = Def {
|
||||
annotation: None,
|
||||
expr_var: t_find_result,
|
||||
loc_expr: no_region(RunLowLevel {
|
||||
op: LowLevel::ListFindUnsafe,
|
||||
args: vec![(t_list, Var(list)), (t_pred_fn, Var(find_predicate))],
|
||||
ret_var: t_find_result,
|
||||
}),
|
||||
loc_pattern: no_region(Pattern::Identifier(find_result)),
|
||||
pattern_vars: Default::default(),
|
||||
};
|
||||
|
||||
let get_value = Access {
|
||||
record_var: t_find_result,
|
||||
ext_var: t_ext_var1,
|
||||
field_var: t_value,
|
||||
loc_expr: Box::new(no_region(Var(find_result))),
|
||||
field: "value".into(),
|
||||
};
|
||||
|
||||
let get_found = Access {
|
||||
record_var: t_find_result,
|
||||
ext_var: t_ext_var2,
|
||||
field_var: t_found,
|
||||
loc_expr: Box::new(no_region(Var(find_result))),
|
||||
field: "found".into(),
|
||||
};
|
||||
|
||||
let make_ok = tag("Ok", vec![get_value], var_store);
|
||||
|
||||
let make_err = tag(
|
||||
"Err",
|
||||
vec![tag("NotFound", Vec::new(), var_store)],
|
||||
var_store,
|
||||
);
|
||||
|
||||
let inspect = If {
|
||||
cond_var: t_bool,
|
||||
branch_var: t_ret,
|
||||
branches: vec![(
|
||||
// if-condition
|
||||
no_region(get_found),
|
||||
no_region(make_ok),
|
||||
)],
|
||||
final_else: Box::new(no_region(make_err)),
|
||||
};
|
||||
|
||||
let body = LetNonRec(
|
||||
Box::new(find_result_def),
|
||||
Box::new(no_region(inspect)),
|
||||
t_ret,
|
||||
);
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(t_list, Symbol::ARG_1), (t_pred_fn, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
t_ret,
|
||||
)
|
||||
}
|
||||
|
||||
/// Dict.hashTestOnly : k, v -> Nat
|
||||
fn dict_hash_test_only(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_2(symbol, LowLevel::Hash, var_store)
|
||||
}
|
||||
|
||||
/// Dict.len : Dict * * -> Nat
|
||||
fn dict_len(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let arg1_var = var_store.fresh();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue