diff options
Diffstat (limited to 'src/libexpr/primops.cc')
-rw-r--r-- | src/libexpr/primops.cc | 101 |
1 files changed, 82 insertions, 19 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index c456e9b96a53..3b965f209bb2 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -477,7 +477,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * bool ignoreNulls = false; attr = args[0]->attrs->find(state.sIgnoreNulls); if (attr != args[0]->attrs->end()) - ignoreNulls = state.forceBool(*attr->value); + ignoreNulls = state.forceBool(*attr->value, pos); /* Build the derivation expression by processing the attributes. */ Derivation drv; @@ -673,6 +673,19 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } +/* Return a placeholder string for the specified output that will be + substituted by the corresponding output path at build time. For + example, ‘placeholder "out"’ returns the string + /1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9. At build + time, any occurence of this string in an derivation attribute will + be replaced with the concrete path in the Nix store of the output + ‘out’. */ +static void prim_placeholder(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + mkString(v, hashPlaceholder(state.forceStringNoCtx(*args[0], pos))); +} + + /************************************************************* * Paths *************************************************************/ @@ -912,9 +925,10 @@ struct FilterFromExpr : PathFilter { EvalState & state; Value & filter; + Pos pos; - FilterFromExpr(EvalState & state, Value & filter) - : state(state), filter(filter) + FilterFromExpr(EvalState & state, Value & filter, const Pos & pos) + : state(state), filter(filter), pos(pos) { } @@ -942,7 +956,7 @@ struct FilterFromExpr : PathFilter Value res; state.callFunction(fun2, arg2, res, noPos); - return state.forceBool(res); + return state.forceBool(res, pos); } }; @@ -958,7 +972,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args if (args[0]->type != tLambda) throw TypeError(format("first argument in call to ‘filterSource’ is not a function but %1%, at %2%") % showType(*args[0]) % pos); - FilterFromExpr filter(state, *args[0]); + FilterFromExpr filter(state, *args[0], pos); path = state.checkSourcePath(path); @@ -1278,7 +1292,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu for (unsigned int n = 0; n < args[1]->listSize(); ++n) { Value res; state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos); - if (state.forceBool(res)) + if (state.forceBool(res, pos)) vs[k++] = args[1]->listElems()[n]; else same = false; @@ -1354,7 +1368,7 @@ static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * arg Value vTmp; for (unsigned int n = 0; n < args[1]->listSize(); ++n) { state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos); - bool res = state.forceBool(vTmp); + bool res = state.forceBool(vTmp, pos); if (res == any) { mkBool(v, any); return; @@ -1420,7 +1434,7 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value Value vTmp1, vTmp2; state.callFunction(*args[0], *a, vTmp1, pos); state.callFunction(vTmp1, *b, vTmp2, pos); - return state.forceBool(vTmp2); + return state.forceBool(vTmp2, pos); }; /* FIXME: std::sort can segfault if the comparator is not a strict @@ -1430,6 +1444,40 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value } +static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + state.forceFunction(*args[0], pos); + state.forceList(*args[1], pos); + + auto len = args[1]->listSize(); + + ValueVector right, wrong; + + for (unsigned int n = 0; n < len; ++n) { + auto vElem = args[1]->listElems()[n]; + state.forceValue(*vElem); + Value res; + state.callFunction(*args[0], *vElem, res, pos); + if (state.forceBool(res, pos)) + right.push_back(vElem); + else + wrong.push_back(vElem); + } + + state.mkAttrs(v, 2); + + Value * vRight = state.allocAttr(v, state.sRight); + state.mkList(*vRight, right.size()); + memcpy(vRight->listElems(), right.data(), sizeof(Value *) * right.size()); + + Value * vWrong = state.allocAttr(v, state.sWrong); + state.mkList(*vWrong, wrong.size()); + memcpy(vWrong->listElems(), wrong.data(), sizeof(Value *) * wrong.size()); + + v.attrs->sort(); +} + + /************************************************************* * Integer arithmetic *************************************************************/ @@ -1620,13 +1668,18 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar if (args[0]->listSize() != args[1]->listSize()) throw EvalError(format("‘from’ and ‘to’ arguments to ‘replaceStrings’ have different lengths, at %1%") % pos); - Strings from; + vector<string> from; + from.reserve(args[0]->listSize()); for (unsigned int n = 0; n < args[0]->listSize(); ++n) - from.push_back(state.forceStringNoCtx(*args[0]->listElems()[n], pos)); + from.push_back(state.forceString(*args[0]->listElems()[n], pos)); - Strings to; - for (unsigned int n = 0; n < args[1]->listSize(); ++n) - to.push_back(state.forceStringNoCtx(*args[1]->listElems()[n], pos)); + vector<std::pair<string, PathSet>> to; + to.reserve(args[1]->listSize()); + for (unsigned int n = 0; n < args[1]->listSize(); ++n) { + PathSet ctx; + auto s = state.forceString(*args[1]->listElems()[n], ctx, pos); + to.push_back(std::make_pair(std::move(s), std::move(ctx))); + } PathSet context; auto s = state.forceString(*args[2], context, pos); @@ -1634,11 +1687,16 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar string res; for (size_t p = 0; p < s.size(); ) { bool found = false; - for (auto i = from.begin(), j = to.begin(); i != from.end(); ++i, ++j) + auto i = from.begin(); + auto j = to.begin(); + for (; i != from.end(); ++i, ++j) if (s.compare(p, i->size(), *i) == 0) { found = true; p += i->size(); - res += *j; + res += j->first; + for (auto& path : j->second) + context.insert(path); + j->second.clear(); break; } if (!found) res += s[p++]; @@ -1682,6 +1740,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, { string url; Hash expectedHash; + string name; state.forceValue(*args[0]); @@ -1690,11 +1749,13 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, state.forceAttrs(*args[0], pos); for (auto & attr : *args[0]->attrs) { - string name(attr.name); - if (name == "url") + string n(attr.name); + if (n == "url") url = state.forceStringNoCtx(*attr.value, *attr.pos); - else if (name == "sha256") + else if (n == "sha256") expectedHash = parseHash16or32(htSHA256, state.forceStringNoCtx(*attr.value, *attr.pos)); + else if (n == "name") + name = state.forceStringNoCtx(*attr.value, *attr.pos); else throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos); } @@ -1708,7 +1769,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, if (state.restricted && !expectedHash) throw Error(format("‘%1%’ is not allowed in restricted mode") % who); - Path res = makeDownloader()->downloadCached(state.store, url, unpack, expectedHash); + Path res = makeDownloader()->downloadCached(state.store, url, unpack, name, expectedHash); mkString(v, res, PathSet({res})); } @@ -1855,6 +1916,7 @@ void EvalState::createBaseEnv() addPrimOp("__all", 2, prim_all); addPrimOp("__genList", 2, prim_genList); addPrimOp("__sort", 2, prim_sort); + addPrimOp("__partition", 2, prim_partition); // Integer arithmetic addPrimOp("__add", 2, prim_add); @@ -1880,6 +1942,7 @@ void EvalState::createBaseEnv() // Derivations addPrimOp("derivationStrict", 1, prim_derivationStrict); + addPrimOp("placeholder", 1, prim_placeholder); // Networking addPrimOp("__fetchurl", 1, prim_fetchurl); |