Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3505,6 +3505,49 @@ static RegisterPrimOp primop_mapAttrs({
.fun = prim_mapAttrs,
});

static void prim_filterAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.filterAttrs");

if (args[1]->attrs()->empty()) {
v = *args[1];
return;
}

state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.filterAttrs");

auto attrs = state.buildBindings(args[1]->attrs()->size());

for (auto & i : *args[1]->attrs()) {
Value * vName = Value::toPtr(state.symbols[i.name]);
Value * callArgs[] = {vName, i.value};
Value res;
state.callFunction(*args[0], callArgs, res, noPos);
if (state.forceBool(
res, pos, "while evaluating the return value of the filtering function passed to builtins.filterAttrs"))
attrs.insert(i.name, i.value);
}

v.mkAttrs(attrs.alreadySorted());
}

static RegisterPrimOp primop_filterAttrs({
.name = "__filterAttrs",
.args = {"f", "attrset"},
.doc = R"(
Return an attribute set consisting of the attributes in *attrset* for which
the function *f* returns `true`. The function *f* is called with two arguments:
the name of the attribute and the value of the attribute. For example,

```nix
builtins.filterAttrs (name: value: name == "foo") { foo = 1; bar = 2; }
```

evaluates to `{ foo = 1; }`.
)",
.fun = prim_filterAttrs,
});

static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
// we will first count how many values are present for each given key.
Expand Down
1 change: 1 addition & 0 deletions tests/functional/lang/eval-okay-filterattrs-names.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ a = 3; }
5 changes: 5 additions & 0 deletions tests/functional/lang/eval-okay-filterattrs-names.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
builtins.filterAttrs (name: value: name == "a") {
a = 3;
b = 6;
c = 10;
}
1 change: 1 addition & 0 deletions tests/functional/lang/eval-okay-filterattrs.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ b = 6; c = 10; }
5 changes: 5 additions & 0 deletions tests/functional/lang/eval-okay-filterattrs.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
builtins.filterAttrs (name: value: value > 5) {
a = 3;
b = 6;
c = 10;
}