@@ -3529,6 +3529,48 @@ static RegisterPrimOp primop_mapAttrs({
35293529 .fun = prim_mapAttrs,
35303530});
35313531
3532+ static void prim_filterAttrs (EvalState & state, const PosIdx pos, Value ** args, Value & v)
3533+ {
3534+ state.forceAttrs (*args[1 ], pos, " while evaluating the second argument passed to builtins.filterAttrs" );
3535+
3536+ if (args[1 ]->attrs ()->empty ()) {
3537+ v = *args[1 ];
3538+ return ;
3539+ }
3540+
3541+ state.forceFunction (*args[0 ], pos, " while evaluating the first argument passed to builtins.filterAttrs" );
3542+
3543+ auto attrs = state.buildBindings (args[1 ]->attrs ()->size ());
3544+
3545+ for (auto & i : *args[1 ]->attrs ()) {
3546+ Value * vName = Value::toPtr (state.symbols [i.name ]);
3547+ Value * vFun2 = state.allocValue ();
3548+ vFun2->mkApp (args[0 ], vName);
3549+ Value res;
3550+ state.callFunction (*vFun2, *i.value , res, noPos);
3551+ if (state.forceBool (
3552+ res, pos, " while evaluating the return value of the filtering function passed to builtins.filterAttrs" ))
3553+ attrs.insert (i.name , i.value );
3554+ }
3555+
3556+ v.mkAttrs (attrs.alreadySorted ());
3557+ }
3558+
3559+ static RegisterPrimOp primop_filterAttrs ({
3560+ .name = " __filterAttrs" ,
3561+ .args = {" f" , " attrset" },
3562+ .doc = R"(
3563+ Return an attribute set consisting of the attributes in *attrset* for which
3564+ the function *f* returns `true`. The function *f* is called with two arguments:
3565+ the name of the attribute and the value of the attribute. For example,
3566+ ```nix
3567+ builtins.filterAttrs (name: value: name == "foo") { foo = 1; bar = 2; }
3568+ ```
3569+ evaluates to `{ foo = 1; }`.
3570+ )" ,
3571+ .fun = prim_filterAttrs,
3572+ });
3573+
35323574static void prim_zipAttrsWith (EvalState & state, const PosIdx pos, Value ** args, Value & v)
35333575{
35343576 // we will first count how many values are present for each given key.
0 commit comments