mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-22 14:06:16 +02:00
* Generalised the dependencyClosure primop to builtins.genericClosure,
which is hopefully more useful. * New primops: length, mul, div.
This commit is contained in:
parent
d567baabbd
commit
7cd88b1dec
5 changed files with 442 additions and 139 deletions
|
@ -17,8 +17,13 @@
|
||||||
<listitem><para><command>nix-store --dump-db / --load-db</command>.</para></listitem>
|
<listitem><para><command>nix-store --dump-db / --load-db</command>.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>New primops:
|
<listitem><para>New primops:
|
||||||
<varname>builtins.parseDrvName</varname> and
|
<varname>builtins.parseDrvName</varname>,
|
||||||
<varname>builtins.compareVersions</varname>.</para></listitem>
|
<varname>builtins.compareVersions</varname>,
|
||||||
|
<varname>builtins.length</varname>,
|
||||||
|
<varname>builtins.add</varname>,
|
||||||
|
<varname>builtins.sub</varname>,
|
||||||
|
<varname>builtins.genericClosure</varname>.
|
||||||
|
</para></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
|
|
@ -128,59 +128,7 @@ static Expr prim_isFunction(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Path findDependency(Path dir, string dep)
|
static Expr prim_genericClosure(EvalState & state, const ATermVector & args)
|
||||||
{
|
|
||||||
if (dep[0] == '/') throw EvalError(
|
|
||||||
format("illegal absolute dependency `%1%'") % dep);
|
|
||||||
|
|
||||||
Path p = canonPath(dir + "/" + dep);
|
|
||||||
|
|
||||||
if (pathExists(p))
|
|
||||||
return p;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Make path `p' relative to directory `pivot'. E.g.,
|
|
||||||
relativise("/a/b/c", "a/b/x/y") => "../x/y". Both input paths
|
|
||||||
should be in absolute canonical form. */
|
|
||||||
static string relativise(Path pivot, Path p)
|
|
||||||
{
|
|
||||||
assert(pivot.size() > 0 && pivot[0] == '/');
|
|
||||||
assert(p.size() > 0 && p[0] == '/');
|
|
||||||
|
|
||||||
if (pivot == p) return ".";
|
|
||||||
|
|
||||||
/* `p' is in `pivot'? */
|
|
||||||
Path pivot2 = pivot + "/";
|
|
||||||
if (p.substr(0, pivot2.size()) == pivot2) {
|
|
||||||
return p.substr(pivot2.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, `p' is in a parent of `pivot'. Find up till which
|
|
||||||
path component `p' and `pivot' match, and add an appropriate
|
|
||||||
number of `..' components. */
|
|
||||||
string::size_type i = 1;
|
|
||||||
while (1) {
|
|
||||||
string::size_type j = pivot.find('/', i);
|
|
||||||
if (j == string::npos) break;
|
|
||||||
j++;
|
|
||||||
if (pivot.substr(0, j) != p.substr(0, j)) break;
|
|
||||||
i = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
string prefix;
|
|
||||||
unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
|
|
||||||
while (slashes--) {
|
|
||||||
prefix += "../";
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix + p.substr(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr prim_dependencyClosure(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
{
|
||||||
startNest(nest, lvlDebug, "finding dependencies");
|
startNest(nest, lvlDebug, "finding dependencies");
|
||||||
|
|
||||||
|
@ -191,87 +139,40 @@ static Expr prim_dependencyClosure(EvalState & state, const ATermVector & args)
|
||||||
if (!startSet) throw EvalError("attribute `startSet' required");
|
if (!startSet) throw EvalError("attribute `startSet' required");
|
||||||
ATermList startSet2 = evalList(state, startSet);
|
ATermList startSet2 = evalList(state, startSet);
|
||||||
|
|
||||||
Path pivot;
|
set<Expr> workSet; // !!! gc roots
|
||||||
PathSet workSet;
|
for (ATermIterator i(startSet2); i; ++i) workSet.insert(*i);
|
||||||
for (ATermIterator i(startSet2); i; ++i) {
|
|
||||||
PathSet context; /* !!! what to do? */
|
|
||||||
Path p = coerceToPath(state, *i, context);
|
|
||||||
workSet.insert(p);
|
|
||||||
pivot = dirOf(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the search path. */
|
/* Get the operator. */
|
||||||
PathSet searchPath;
|
Expr op = queryAttr(attrs, "operator");
|
||||||
Expr e = queryAttr(attrs, "searchPath");
|
if (!op) throw EvalError("attribute `operator' required");
|
||||||
if (e) {
|
|
||||||
ATermList list = evalList(state, e);
|
|
||||||
for (ATermIterator i(list); i; ++i) {
|
|
||||||
PathSet context; /* !!! what to do? */
|
|
||||||
Path p = coerceToPath(state, *i, context);
|
|
||||||
searchPath.insert(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr scanner = queryAttr(attrs, "scanner");
|
/* Construct the closure by applying the operator to element of
|
||||||
if (!scanner) throw EvalError("attribute `scanner' required");
|
`workSet', adding the result to `workSet', continuing until
|
||||||
|
no new elements are found. */
|
||||||
/* Construct the dependency closure by querying the dependency of
|
ATermList res = ATempty;
|
||||||
each path in `workSet', adding the dependencies to
|
set<Expr> doneKeys; // !!! gc roots
|
||||||
`workSet'. */
|
|
||||||
PathSet doneSet;
|
|
||||||
while (!workSet.empty()) {
|
while (!workSet.empty()) {
|
||||||
Path path = *(workSet.begin());
|
Expr e = *(workSet.begin());
|
||||||
workSet.erase(path);
|
workSet.erase(e);
|
||||||
|
|
||||||
if (doneSet.find(path) != doneSet.end()) continue;
|
e = strictEvalExpr(state, e);
|
||||||
doneSet.insert(path);
|
|
||||||
|
|
||||||
try {
|
Expr key = queryAttr(e, "key");
|
||||||
|
if (!key) throw EvalError("attribute `key' required");
|
||||||
|
|
||||||
/* Call the `scanner' function with `path' as argument. */
|
if (doneKeys.find(key) != doneKeys.end()) continue;
|
||||||
debug(format("finding dependencies in `%1%'") % path);
|
doneKeys.insert(key);
|
||||||
ATermList deps = evalList(state, makeCall(scanner, makeStr(path)));
|
res = ATinsert(res, e);
|
||||||
|
|
||||||
|
/* Call the `operator' function with `e' as argument. */
|
||||||
|
ATermList res = evalList(state, makeCall(op, e));
|
||||||
|
|
||||||
/* Try to find the dependencies relative to the `path'. */
|
/* Try to find the dependencies relative to the `path'. */
|
||||||
for (ATermIterator i(deps); i; ++i) {
|
for (ATermIterator i(res); i; ++i)
|
||||||
string s = evalStringNoCtx(state, *i);
|
workSet.insert(evalExpr(state, *i));
|
||||||
|
|
||||||
Path dep = findDependency(dirOf(path), s);
|
|
||||||
|
|
||||||
if (dep == "") {
|
|
||||||
for (PathSet::iterator j = searchPath.begin();
|
|
||||||
j != searchPath.end(); ++j)
|
|
||||||
{
|
|
||||||
dep = findDependency(*j, s);
|
|
||||||
if (dep != "") break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dep == "")
|
return makeList(res);
|
||||||
debug(format("did NOT find dependency `%1%'") % s);
|
|
||||||
else {
|
|
||||||
debug(format("found dependency `%1%'") % dep);
|
|
||||||
workSet.insert(dep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Error & e) {
|
|
||||||
e.addPrefix(format("while finding dependencies in `%1%':\n")
|
|
||||||
% path);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a list of the dependencies we've just found. */
|
|
||||||
ATermList deps = ATempty;
|
|
||||||
for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) {
|
|
||||||
deps = ATinsert(deps, makeStr(relativise(pivot, *i)));
|
|
||||||
deps = ATinsert(deps, makeStr(*i));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(format("dependency list is `%1%'") % makeList(deps));
|
|
||||||
|
|
||||||
return makeList(deps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -311,15 +212,6 @@ static Expr prim_trace(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr prim_relativise(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
PathSet context; /* !!! what to do? */
|
|
||||||
Path pivot = coerceToPath(state, args[0], context);
|
|
||||||
Path path = coerceToPath(state, args[1], context);
|
|
||||||
return makeStr(relativise(pivot, path));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Derivations
|
* Derivations
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
@ -874,6 +766,14 @@ static Expr prim_map(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the length of a list. This is an O(1) time operation. */
|
||||||
|
static Expr prim_length(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
ATermList list = evalList(state, args[0]);
|
||||||
|
return makeInt(ATgetLength(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Integer arithmetic
|
* Integer arithmetic
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
@ -895,6 +795,23 @@ static Expr prim_sub(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr prim_mul(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
int i1 = evalInt(state, args[0]);
|
||||||
|
int i2 = evalInt(state, args[1]);
|
||||||
|
return makeInt(i1 * i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr prim_div(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
int i1 = evalInt(state, args[0]);
|
||||||
|
int i2 = evalInt(state, args[1]);
|
||||||
|
if (i2 == 0) throw EvalError("division by zero");
|
||||||
|
return makeInt(i1 / i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr prim_lessThan(EvalState & state, const ATermVector & args)
|
static Expr prim_lessThan(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
int i1 = evalInt(state, args[0]);
|
int i1 = evalInt(state, args[0]);
|
||||||
|
@ -1019,7 +936,7 @@ void EvalState::addPrimOps()
|
||||||
addPrimOp("import", 1, prim_import);
|
addPrimOp("import", 1, prim_import);
|
||||||
addPrimOp("isNull", 1, prim_isNull);
|
addPrimOp("isNull", 1, prim_isNull);
|
||||||
addPrimOp("__isFunction", 1, prim_isFunction);
|
addPrimOp("__isFunction", 1, prim_isFunction);
|
||||||
addPrimOp("dependencyClosure", 1, prim_dependencyClosure);
|
addPrimOp("__genericClosure", 1, prim_genericClosure);
|
||||||
addPrimOp("abort", 1, prim_abort);
|
addPrimOp("abort", 1, prim_abort);
|
||||||
addPrimOp("throw", 1, prim_throw);
|
addPrimOp("throw", 1, prim_throw);
|
||||||
addPrimOp("__getEnv", 1, prim_getEnv);
|
addPrimOp("__getEnv", 1, prim_getEnv);
|
||||||
|
@ -1029,8 +946,6 @@ void EvalState::addPrimOps()
|
||||||
addPrimOp("__exprToString", 1, prim_exprToString);
|
addPrimOp("__exprToString", 1, prim_exprToString);
|
||||||
addPrimOp("__stringToExpr", 1, prim_stringToExpr);
|
addPrimOp("__stringToExpr", 1, prim_stringToExpr);
|
||||||
|
|
||||||
addPrimOp("relativise", 2, prim_relativise);
|
|
||||||
|
|
||||||
// Derivations
|
// Derivations
|
||||||
addPrimOp("derivation!", 1, prim_derivationStrict);
|
addPrimOp("derivation!", 1, prim_derivationStrict);
|
||||||
addPrimOp("derivation", 1, prim_derivationLazy);
|
addPrimOp("derivation", 1, prim_derivationLazy);
|
||||||
|
@ -1060,10 +975,13 @@ void EvalState::addPrimOps()
|
||||||
addPrimOp("__head", 1, prim_head);
|
addPrimOp("__head", 1, prim_head);
|
||||||
addPrimOp("__tail", 1, prim_tail);
|
addPrimOp("__tail", 1, prim_tail);
|
||||||
addPrimOp("map", 2, prim_map);
|
addPrimOp("map", 2, prim_map);
|
||||||
|
addPrimOp("__length", 1, prim_length);
|
||||||
|
|
||||||
// Integer arithmetic
|
// Integer arithmetic
|
||||||
addPrimOp("__add", 2, prim_add);
|
addPrimOp("__add", 2, prim_add);
|
||||||
addPrimOp("__sub", 2, prim_sub);
|
addPrimOp("__sub", 2, prim_sub);
|
||||||
|
addPrimOp("__mul", 2, prim_mul);
|
||||||
|
addPrimOp("__div", 2, prim_div);
|
||||||
addPrimOp("__lessThan", 2, prim_lessThan);
|
addPrimOp("__lessThan", 2, prim_lessThan);
|
||||||
|
|
||||||
// String manipulation
|
// String manipulation
|
||||||
|
|
343
tests/lang/eval-okay-closure.exp.xml
Normal file
343
tests/lang/eval-okay-closure.exp.xml
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<expr>
|
||||||
|
<list>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-13" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-12" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-11" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-9" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-8" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-7" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-5" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-4" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-3" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="-1" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="0" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="1" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="2" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="4" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="5" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="6" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="8" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="9" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="10" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="13" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="14" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="15" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="17" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="18" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="19" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="22" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="23" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="26" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="27" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="28" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="31" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="32" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="35" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="36" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="40" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="41" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="44" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="45" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="49" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="53" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="54" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="58" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="62" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="foo">
|
||||||
|
<bool value="true" />
|
||||||
|
</attr>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="67" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="71" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
<attrs>
|
||||||
|
<attr name="key">
|
||||||
|
<int value="80" />
|
||||||
|
</attr>
|
||||||
|
</attrs>
|
||||||
|
</list>
|
||||||
|
</expr>
|
13
tests/lang/eval-okay-closure.nix
Normal file
13
tests/lang/eval-okay-closure.nix
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
let
|
||||||
|
|
||||||
|
closure = builtins.genericClosure {
|
||||||
|
startSet = [{key = 80;}];
|
||||||
|
operator = {key, foo ? false}:
|
||||||
|
if builtins.lessThan key 0
|
||||||
|
then []
|
||||||
|
else [{key = builtins.sub key 9;} {key = builtins.sub key 13; foo = true;}];
|
||||||
|
};
|
||||||
|
|
||||||
|
sort = (import ./lib.nix).sortBy (a: b: builtins.lessThan a.key b.key);
|
||||||
|
|
||||||
|
in sort closure
|
|
@ -25,4 +25,28 @@ rec {
|
||||||
in !(lessThan lenFileName lenExt) &&
|
in !(lessThan lenFileName lenExt) &&
|
||||||
substring (sub lenFileName lenExt) lenFileName fileName == ext;
|
substring (sub lenFileName lenExt) lenFileName fileName == ext;
|
||||||
|
|
||||||
|
# Split a list at the given position.
|
||||||
|
splitAt = pos: list:
|
||||||
|
if pos == 0 then {first = []; second = list;} else
|
||||||
|
if list == [] then {first = []; second = [];} else
|
||||||
|
let res = splitAt (sub pos 1) (tail list);
|
||||||
|
in {first = [(head list)] ++ res.first; second = res.second;};
|
||||||
|
|
||||||
|
# Stable merge sort.
|
||||||
|
sortBy = comp: list:
|
||||||
|
if lessThan 1 (length list)
|
||||||
|
then
|
||||||
|
let
|
||||||
|
split = splitAt (div (length list) 2) list;
|
||||||
|
first = sortBy comp split.first;
|
||||||
|
second = sortBy comp split.second;
|
||||||
|
in mergeLists comp first second
|
||||||
|
else list;
|
||||||
|
|
||||||
|
mergeLists = comp: list1: list2:
|
||||||
|
if list1 == [] then list2 else
|
||||||
|
if list2 == [] then list1 else
|
||||||
|
if comp (head list2) (head list1) then [(head list2)] ++ mergeLists comp list1 (tail list2) else
|
||||||
|
[(head list1)] ++ mergeLists comp (tail list1) list2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue