diff options
Diffstat (limited to 'src/libexpr/primops.cc')
-rw-r--r-- | src/libexpr/primops.cc | 104 |
1 files changed, 65 insertions, 39 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 5b9ecc018f0e..3c899d769253 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1,15 +1,15 @@ +#include "archive.hh" +#include "derivations.hh" +#include "download.hh" +#include "eval-inline.hh" #include "eval.hh" -#include "misc.hh" #include "globals.hh" +#include "json-to-value.hh" +#include "names.hh" #include "store-api.hh" #include "util.hh" -#include "archive.hh" -#include "value-to-xml.hh" #include "value-to-json.hh" -#include "json-to-value.hh" -#include "names.hh" -#include "eval-inline.hh" -#include "download.hh" +#include "value-to-xml.hh" #include <sys/types.h> #include <sys/stat.h> @@ -43,7 +43,7 @@ std::pair<string, string> decodeContext(const string & s) InvalidPathError::InvalidPathError(const Path & path) : EvalError(format("path ‘%1%’ is not valid") % path), path(path) {} -void realiseContext(const PathSet & context) +void EvalState::realiseContext(const PathSet & context) { PathSet drvs; for (auto & i : context) { @@ -52,16 +52,14 @@ void realiseContext(const PathSet & context) assert(isStorePath(ctx)); if (!store->isValidPath(ctx)) throw InvalidPathError(ctx); - if (!decoded.second.empty() && isDerivation(ctx)) + if (!decoded.second.empty() && nix::isDerivation(ctx)) drvs.insert(decoded.first + "!" + decoded.second); } if (!drvs.empty()) { /* For performance, prefetch all substitute info. */ PathSet willBuild, willSubstitute, unknown; unsigned long long downloadSize, narSize; - queryMissing(*store, drvs, - willBuild, willSubstitute, unknown, downloadSize, narSize); - + store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize); store->buildPaths(drvs); } } @@ -75,7 +73,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args Path path = state.coerceToPath(pos, *args[1], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -83,7 +81,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args path = state.checkSourcePath(path); - if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) { + if (isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) { Derivation drv = readDerivation(path); Value & w = *state.allocValue(); state.mkAttrs(w, 3 + drv.outputs.size()); @@ -145,7 +143,7 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args Path path = state.coerceToPath(pos, *args[0], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -197,6 +195,7 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu case tExternal: t = args[0]->external->typeOf(); break; + case tFloat: t = "float"; break; default: abort(); } mkString(v, state.symbols.create(t)); @@ -226,6 +225,12 @@ static void prim_isInt(EvalState & state, const Pos & pos, Value * * args, Value mkBool(v, args[0]->type == tInt); } +/* Determine whether the argument is a float. */ +static void prim_isFloat(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + state.forceValue(*args[0]); + mkBool(v, args[0]->type == tFloat); +} /* Determine whether the argument is a string. */ static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v) @@ -247,11 +252,17 @@ struct CompareValues { bool operator () (const Value * v1, const Value * v2) const { + if (v1->type == tFloat && v2->type == tInt) + return v1->fpoint < v2->integer; + if (v1->type == tInt && v2->type == tFloat) + return v1->integer < v2->fpoint; if (v1->type != v2->type) - throw EvalError("cannot compare values of different types"); + throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2)); switch (v1->type) { case tInt: return v1->integer < v2->integer; + case tFloat: + return v1->fpoint < v2->fpoint; case tString: return strcmp(v1->string.s, v2->string.s) < 0; case tPath: @@ -560,11 +571,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * runs. */ if (path.at(0) == '=') { /* !!! This doesn't work if readOnlyMode is set. */ - PathSet refs; computeFSClosure(*store, string(path, 1), refs); + PathSet refs; + state.store->computeFSClosure(string(path, 1), refs); for (auto & j : refs) { drv.inputSrcs.insert(j); if (isDerivation(j)) - drv.inputDrvs[j] = store->queryDerivationOutputNames(j); + drv.inputDrvs[j] = state.store->queryDerivationOutputNames(j); } } @@ -581,7 +593,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Handle derivation contexts returned by ‘builtins.storePath’. */ else if (isDerivation(path)) - drv.inputDrvs[path] = store->queryDerivationOutputNames(path); + drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path); /* Otherwise it's a source file. */ else @@ -630,7 +642,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Use the masked derivation expression to compute the output path. */ - Hash h = hashDerivationModulo(*store, drv); + Hash h = hashDerivationModulo(*state.store, drv); for (auto & i : drv.outputs) if (i.second.path == "") { @@ -641,7 +653,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } /* Write the resulting term into the Nix store directory. */ - Path drvPath = writeDerivation(*store, drv, drvName, state.repair); + Path drvPath = writeDerivation(state.store, drv, drvName, state.repair); printMsg(lvlChatty, format("instantiated ‘%1%’ -> ‘%2%’") % drvName % drvPath); @@ -649,7 +661,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Optimisation, but required in read-only mode! because in that case we don't actually write store derivations, so we can't read them later. */ - drvHashes[drvPath] = hashDerivationModulo(*store, drv); + drvHashes[drvPath] = hashDerivationModulo(*state.store, drv); state.mkAttrs(v, 1 + drv.outputs.size()); mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath)); @@ -695,7 +707,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V throw EvalError(format("path ‘%1%’ is not in the Nix store, at %2%") % path % pos); Path path2 = toStorePath(path); if (!settings.readOnlyMode) - store->ensurePath(path2); + state.store->ensurePath(path2); context.insert(path2); mkString(v, path, context); } @@ -745,7 +757,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va PathSet context; Path path = state.coerceToPath(pos, *args[0], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -786,7 +798,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va string path = state.forceStringNoCtx(*args[1], pos); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -801,7 +813,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val PathSet ctx; Path path = state.coerceToPath(pos, *args[0], ctx); try { - realiseContext(ctx); + state.realiseContext(ctx); } catch (InvalidPathError & e) { throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -879,13 +891,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu if (path.at(0) != '~') throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos); path = string(path, 1); - } + } refs.insert(path); } Path storePath = settings.readOnlyMode ? computeStorePathForText(name, contents, refs) - : store->addTextToStore(name, contents, refs, state.repair); + : state.store->addTextToStore(name, contents, refs, state.repair); /* Note: we don't need to add `context' to the context of the result, since `storePath' itself has references to the paths @@ -951,7 +963,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args Path dstPath = settings.readOnlyMode ? computeStorePathForPath(path, true, htSHA256, filter).first - : store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); + : state.store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); mkString(v, dstPath, singleton<PathSet>(dstPath)); } @@ -1154,7 +1166,7 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va /* Return a set containing the names of the formal arguments expected by the function `f'. The value of each attribute is a Boolean - denoting whether has a default value. For instance, + denoting whether the corresponding argument has a default value. For instance, functionArgs ({ x, y ? 123}: ...) => { x = false; y = true; } @@ -1374,7 +1386,7 @@ static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Val state.mkList(v, len); - for (unsigned int n = 0; n < len; ++n) { + for (unsigned int n = 0; n < (unsigned int) len; ++n) { Value * arg = state.allocValue(); mkInt(*arg, n); mkApp(*(v.listElems()[n] = state.allocValue()), *args[0], *arg); @@ -1424,27 +1436,40 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & v) { - mkInt(v, state.forceInt(*args[0], pos) + state.forceInt(*args[1], pos)); + if (args[0]->type == tFloat || args[1]->type == tFloat) + mkFloat(v, state.forceFloat(*args[0], pos) + state.forceFloat(*args[1], pos)); + else + mkInt(v, state.forceInt(*args[0], pos) + state.forceInt(*args[1], pos)); } static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & v) { - mkInt(v, state.forceInt(*args[0], pos) - state.forceInt(*args[1], pos)); + if (args[0]->type == tFloat || args[1]->type == tFloat) + mkFloat(v, state.forceFloat(*args[0], pos) - state.forceFloat(*args[1], pos)); + else + mkInt(v, state.forceInt(*args[0], pos) - state.forceInt(*args[1], pos)); } static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & v) { - mkInt(v, state.forceInt(*args[0], pos) * state.forceInt(*args[1], pos)); + if (args[0]->type == tFloat || args[1]->type == tFloat) + mkFloat(v, state.forceFloat(*args[0], pos) * state.forceFloat(*args[1], pos)); + else + mkInt(v, state.forceInt(*args[0], pos) * state.forceInt(*args[1], pos)); } static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & v) { - NixInt i2 = state.forceInt(*args[1], pos); - if (i2 == 0) throw EvalError(format("division by zero, at %1%") % pos); - mkInt(v, state.forceInt(*args[0], pos) / i2); + NixFloat f2 = state.forceFloat(*args[1], pos); + if (f2 == 0) throw EvalError(format("division by zero, at %1%") % pos); + + if (args[0]->type == tFloat || args[1]->type == tFloat) + mkFloat(v, state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); + else + mkInt(v, state.forceInt(*args[0], pos) / state.forceInt(*args[1], pos)); } @@ -1678,7 +1703,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, } else url = state.forceStringNoCtx(*args[0], pos); - Path res = downloadFileCached(url, unpack); + Path res = downloadFileCached(state.store, url, unpack); mkString(v, res, PathSet({res})); } @@ -1736,7 +1761,7 @@ void EvalState::createBaseEnv() language feature gets added. It's not necessary to increase it when primops get added, because you can just use `builtins ? primOp' to check. */ - mkInt(v, 3); + mkInt(v, 4); addConstant("__langVersion", v); // Miscellaneous @@ -1753,6 +1778,7 @@ void EvalState::createBaseEnv() addPrimOp("__isFunction", 1, prim_isFunction); addPrimOp("__isString", 1, prim_isString); addPrimOp("__isInt", 1, prim_isInt); + addPrimOp("__isFloat", 1, prim_isFloat); addPrimOp("__isBool", 1, prim_isBool); addPrimOp("__genericClosure", 1, prim_genericClosure); addPrimOp("abort", 1, prim_abort); |