diff options
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/eval.cc | 28 | ||||
-rw-r--r-- | src/libexpr/eval.hh | 15 | ||||
-rw-r--r-- | src/libexpr/get-drvs.cc | 2 | ||||
-rw-r--r-- | src/libexpr/json-to-value.cc | 9 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 101 | ||||
-rw-r--r-- | src/libexpr/value-to-json.cc | 55 | ||||
-rw-r--r-- | src/libexpr/value-to-json.hh | 71 | ||||
-rw-r--r-- | src/libexpr/value.hh | 17 |
8 files changed, 153 insertions, 145 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0833603b2a9e..64f3874db614 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -293,6 +293,8 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store) , sColumn(symbols.create("column")) , sFunctor(symbols.create("__functor")) , sToString(symbols.create("__toString")) + , sRight(symbols.create("right")) + , sWrong(symbols.create("wrong")) , store(store) , baseEnv(allocEnv(128)) , staticBaseEnv(false, 0) @@ -379,9 +381,9 @@ void EvalState::addPrimOp(const string & name, } -void EvalState::getBuiltin(const string & name, Value & v) +Value & EvalState::getBuiltin(const string & name) { - v = *baseEnv.values[0]->attrs->find(symbols.create(name))->value; + return *baseEnv.values[0]->attrs->find(symbols.create(name))->value; } @@ -462,7 +464,7 @@ void mkString(Value & v, const char * s) } -void mkString(Value & v, const string & s, const PathSet & context) +Value & mkString(Value & v, const string & s, const PathSet & context) { mkString(v, s.c_str()); if (!context.empty()) { @@ -473,6 +475,7 @@ void mkString(Value & v, const string & s, const PathSet & context) v.string.context[n++] = dupString(i.c_str()); v.string.context[n] = 0; } + return v; } @@ -993,11 +996,18 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po if (fun.type == tAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { + /* fun may be allocated on the stack of the calling function, + * but for functors we may keep a reference, so heap-allocate + * a copy and use that instead. + */ + auto & fun2 = *allocValue(); + fun2 = fun; + /* !!! Should we use the attr pos here? */ forceValue(*found->value, pos); - Value * v2 = allocValue(); - callFunction(*found->value, fun, *v2, pos); - forceValue(*v2, pos); - return callFunction(*v2, arg, v, pos); + Value v2; + callFunction(*found->value, fun2, v2, pos); + forceValue(v2, pos); + return callFunction(v2, arg, v, pos); } } @@ -1368,11 +1378,11 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) } -bool EvalState::forceBool(Value & v) +bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v); if (v.type != tBool) - throwTypeError("value is %1% while a Boolean was expected", v); + throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos); return v.boolean; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 80e369f2d68f..195cb0db3acc 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -8,10 +8,6 @@ #include <map> -#if HAVE_BOEHMGC -#include <gc/gc_allocator.h> -#endif - namespace nix { @@ -43,7 +39,7 @@ struct Env }; -void mkString(Value & v, const string & s, const PathSet & context = PathSet()); +Value & mkString(Value & v, const string & s, const PathSet & context = PathSet()); void copyContext(const Value & v, PathSet & context); @@ -71,7 +67,8 @@ public: const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, - sFile, sLine, sColumn, sFunctor, sToString; + sFile, sLine, sColumn, sFunctor, sToString, + sRight, sWrong; Symbol sDerivationNix; /* If set, force copying files to the Nix store even if they @@ -108,6 +105,8 @@ public: void addToSearchPath(const string & s); + SearchPath getSearchPath() { return searchPath; } + Path checkSourcePath(const Path & path); /* Parse a Nix expression from the specified file. */ @@ -154,7 +153,7 @@ public: /* Force `v', and then verify that it has the expected type. */ NixInt forceInt(Value & v, const Pos & pos); NixFloat forceFloat(Value & v, const Pos & pos); - bool forceBool(Value & v); + bool forceBool(Value & v, const Pos & pos); inline void forceAttrs(Value & v); inline void forceAttrs(Value & v, const Pos & pos); inline void forceList(Value & v); @@ -204,7 +203,7 @@ private: public: - void getBuiltin(const string & name, Value & v); + Value & getBuiltin(const string & name); private: diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index b06c539de0fb..dc5def911ca0 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -301,7 +301,7 @@ static void getDerivations(EvalState & state, Value & vIn, `recurseForDerivations = true' attribute. */ if (v2.type == tAttrs) { Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations")); - if (j != v2.attrs->end() && state.forceBool(*j->value)) + if (j != v2.attrs->end() && state.forceBool(*j->value, *j->pos)) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); } } diff --git a/src/libexpr/json-to-value.cc b/src/libexpr/json-to-value.cc index 1daf84600dca..f671802bcc24 100644 --- a/src/libexpr/json-to-value.cc +++ b/src/libexpr/json-to-value.cc @@ -12,15 +12,6 @@ static void skipWhitespace(const char * & s) } -#if HAVE_BOEHMGC -typedef std::vector<Value *, gc_allocator<Value *> > ValueVector; -typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap; -#else -typedef std::vector<Value *> ValueVector; -typedef std::map<Symbol, Value *> ValueMap; -#endif - - static string parseJSONString(const char * & s) { string res; 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); diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 47ee324a6e4f..72e413e4491e 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -1,4 +1,5 @@ #include "value-to-json.hh" +#include "json.hh" #include "eval-inline.hh" #include "util.hh" @@ -8,24 +9,8 @@ namespace nix { - -void escapeJSON(std::ostream & str, const string & s) -{ - str << "\""; - for (auto & i : s) - if (i == '\"' || i == '\\') str << "\\" << i; - else if (i == '\n') str << "\\n"; - else if (i == '\r') str << "\\r"; - else if (i == '\t') str << "\\t"; - else if (i >= 0 && i < 32) - str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) i << std::dec; - else str << i; - str << "\""; -} - - void printValueAsJSON(EvalState & state, bool strict, - Value & v, std::ostream & str, PathSet & context) + Value & v, JSONPlaceholder & out, PathSet & context) { checkInterrupt(); @@ -34,58 +19,58 @@ void printValueAsJSON(EvalState & state, bool strict, switch (v.type) { case tInt: - str << v.integer; + out.write(v.integer); break; case tBool: - str << (v.boolean ? "true" : "false"); + out.write(v.boolean); break; case tString: copyContext(v, context); - escapeJSON(str, v.string.s); + out.write(v.string.s); break; case tPath: - escapeJSON(str, state.copyPathToStore(context, v.path)); + out.write(state.copyPathToStore(context, v.path)); break; case tNull: - str << "null"; + out.write(nullptr); break; case tAttrs: { Bindings::iterator i = v.attrs->find(state.sOutPath); if (i == v.attrs->end()) { - JSONObject json(str); + auto obj(out.object()); StringSet names; for (auto & j : *v.attrs) names.insert(j.name); for (auto & j : names) { Attr & a(*v.attrs->find(state.symbols.create(j))); - json.attr(j); - printValueAsJSON(state, strict, *a.value, str, context); + auto placeholder(obj.placeholder(j)); + printValueAsJSON(state, strict, *a.value, placeholder, context); } } else - printValueAsJSON(state, strict, *i->value, str, context); + printValueAsJSON(state, strict, *i->value, out, context); break; } case tList1: case tList2: case tListN: { - JSONList json(str); + auto list(out.list()); for (unsigned int n = 0; n < v.listSize(); ++n) { - json.elem(); - printValueAsJSON(state, strict, *v.listElems()[n], str, context); + auto placeholder(list.placeholder()); + printValueAsJSON(state, strict, *v.listElems()[n], placeholder, context); } break; } case tExternal: - v.external->printValueAsJSON(state, strict, str, context); + v.external->printValueAsJSON(state, strict, out, context); break; case tFloat: - str << v.fpoint; + out.write(v.fpoint); break; default: @@ -93,9 +78,15 @@ void printValueAsJSON(EvalState & state, bool strict, } } +void printValueAsJSON(EvalState & state, bool strict, + Value & v, std::ostream & str, PathSet & context) +{ + JSONPlaceholder out(str); + printValueAsJSON(state, strict, v, out, context); +} void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, - std::ostream & str, PathSet & context) const + JSONPlaceholder & out, PathSet & context) const { throw TypeError(format("cannot convert %1% to JSON") % showType()); } diff --git a/src/libexpr/value-to-json.hh b/src/libexpr/value-to-json.hh index c59caf5641bc..67fed6487dd9 100644 --- a/src/libexpr/value-to-json.hh +++ b/src/libexpr/value-to-json.hh @@ -8,73 +8,12 @@ namespace nix { -void printValueAsJSON(EvalState & state, bool strict, - Value & v, std::ostream & out, PathSet & context); - -void escapeJSON(std::ostream & str, const string & s); +class JSONPlaceholder; -struct JSONObject -{ - std::ostream & str; - bool first; - JSONObject(std::ostream & str) : str(str), first(true) - { - str << "{"; - } - ~JSONObject() - { - str << "}"; - } - void attr(const string & s) - { - if (!first) str << ","; else first = false; - escapeJSON(str, s); - str << ":"; - } - void attr(const string & s, const string & t) - { - attr(s); - escapeJSON(str, t); - } - void attr(const string & s, const char * t) - { - attr(s); - escapeJSON(str, t); - } - void attr(const string & s, bool b) - { - attr(s); - str << (b ? "true" : "false"); - } - template<typename T> - void attr(const string & s, const T & n) - { - attr(s); - str << n; - } -}; +void printValueAsJSON(EvalState & state, bool strict, + Value & v, JSONPlaceholder & out, PathSet & context); -struct JSONList -{ - std::ostream & str; - bool first; - JSONList(std::ostream & str) : str(str), first(true) - { - str << "["; - } - ~JSONList() - { - str << "]"; - } - void elem() - { - if (!first) str << ","; else first = false; - } - void elem(const string & s) - { - elem(); - escapeJSON(str, s); - } -}; +void printValueAsJSON(EvalState & state, bool strict, + Value & v, std::ostream & str, PathSet & context); } diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 62bdd9281f08..271e6a1b24a2 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -1,7 +1,12 @@ #pragma once +#include "config.h" #include "symbol-table.hh" +#if HAVE_BOEHMGC +#include <gc/gc_allocator.h> +#endif + namespace nix { @@ -36,6 +41,7 @@ class Symbol; struct Pos; class EvalState; class XMLWriter; +class JSONPlaceholder; typedef long NixInt; @@ -73,7 +79,7 @@ class ExternalValueBase /* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */ virtual void printValueAsJSON(EvalState & state, bool strict, - std::ostream & str, PathSet & context) const; + JSONPlaceholder & out, PathSet & context) const; /* Print the value as XML. Defaults to unevaluated */ virtual void printValueAsXML(EvalState & state, bool strict, bool location, @@ -249,4 +255,13 @@ void mkPath(Value & v, const char * s); size_t valueSize(Value & v); +#if HAVE_BOEHMGC +typedef std::vector<Value *, gc_allocator<Value *> > ValueVector; +typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap; +#else +typedef std::vector<Value *> ValueVector; +typedef std::map<Symbol, Value *> ValueMap; +#endif + + } |