-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnix-builtins.genericClosure.cc.js
103 lines (78 loc) · 2.74 KB
/
nix-builtins.genericClosure.cc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// javascript version of nix builtins.genericClosure
function genericClosure(arg0) {
// Ensure attributes are forced
if (!arg0 || typeof arg0 != "object") {
throw new Error("while evaluating the first argument passed to builtins.genericClosure");
}
// Get the start set
const startSet = arg0.startSet;
if (startSet === undefined) {
throw new Error("in the attrset passed as argument to builtins.genericClosure");
}
if (!Array.isArray(startSet)) {
throw new Error("while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure");
}
// aka "stack"
const workSet = [...startSet];
// noop
if (startSet.length == 0) {
return startSet;
}
// Get the operator
const operator = arg0.operator;
if (operator === undefined) {
throw new Error("in the attrset passed as argument to builtins.genericClosure");
}
if (typeof operator != "function") {
throw new Error("while evaluating the 'operator' attribute passed as argument to builtins.genericClosure");
}
const result = [];
const doneKeys = new Set();
// Construct the closure by applying the operator to elements of `workSet`
while (workSet.length > 0) {
const element = workSet.shift();
/*
if (element === undefined || typeof element != "object") {
throw new Error("while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure");
}
*/
const key = element.key;
if (key === undefined) {
throw new Error("in one of the attrsets generated by (or initially passed to) builtins.genericClosure");
}
if (doneKeys.has(key)) continue;
doneKeys.add(key.value);
result.push(element);
// Call the `operator` function with `element` as argument
const newElements = operator(element);
/*
if (!Array.isArray(newElements)) {
throw new Error("while evaluating the return value of the `operator` passed to builtins.genericClosure");
}
*/
// Add the values returned by the operator to the work set
for (const element of newElements) {
if (element === undefined) {
throw new Error("while evaluating one of the elements returned by the `operator` passed to builtins.genericClosure");
}
workSet.push(element);
}
}
return result;
}
// demo
console.dir(
genericClosure({
startSet: [
{key: 1},
],
operator: function (element) {
const newElements = [];
console.dir({element});
if (element.key == 1) {
newElements.push({key: 2});
}
return newElements;
},
})
);