2012-07-18 18:59:03 +00:00
|
|
|
|
#pragma once
|
2003-10-30 16:48:26 +00:00
|
|
|
|
|
2015-07-14 17:18:56 +00:00
|
|
|
|
#include "attr-set.hh"
|
2022-01-21 15:20:54 +00:00
|
|
|
|
#include "types.hh"
|
2012-01-07 17:26:33 +00:00
|
|
|
|
#include "value.hh"
|
2003-11-18 12:06:07 +00:00
|
|
|
|
#include "nixexpr.hh"
|
2010-04-13 12:25:42 +00:00
|
|
|
|
#include "symbol-table.hh"
|
2018-03-27 17:02:22 +00:00
|
|
|
|
#include "config.hh"
|
2021-10-25 13:53:01 +00:00
|
|
|
|
#include "experimental-features.hh"
|
2003-10-30 16:48:26 +00:00
|
|
|
|
|
2010-10-04 17:55:38 +00:00
|
|
|
|
#include <map>
|
2019-10-27 09:15:51 +00:00
|
|
|
|
#include <optional>
|
2018-05-22 11:02:14 +00:00
|
|
|
|
#include <unordered_map>
|
2019-11-14 17:32:11 +00:00
|
|
|
|
#include <mutex>
|
2010-10-04 17:55:38 +00:00
|
|
|
|
|
2003-10-30 16:48:26 +00:00
|
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
|
|
|
2022-03-12 00:28:00 +00:00
|
|
|
|
struct Store;
|
2010-03-29 14:37:56 +00:00
|
|
|
|
class EvalState;
|
2020-06-17 17:26:37 +00:00
|
|
|
|
class StorePath;
|
2017-06-28 16:11:01 +00:00
|
|
|
|
enum RepairFlag : bool;
|
2019-05-29 13:31:07 +00:00
|
|
|
|
|
2010-10-24 00:41:29 +00:00
|
|
|
|
|
2014-04-04 16:51:01 +00:00
|
|
|
|
typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v);
|
2010-10-23 20:07:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct PrimOp
|
|
|
|
|
{
|
|
|
|
|
PrimOpFun fun;
|
2016-04-13 09:15:45 +00:00
|
|
|
|
size_t arity;
|
2010-10-23 20:07:47 +00:00
|
|
|
|
Symbol name;
|
2020-08-24 11:11:56 +00:00
|
|
|
|
std::vector<std::string> args;
|
|
|
|
|
const char * doc = nullptr;
|
2010-10-23 20:07:47 +00:00
|
|
|
|
};
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
|
|
|
|
|
2010-04-14 14:42:32 +00:00
|
|
|
|
struct Env
|
|
|
|
|
{
|
|
|
|
|
Env * up;
|
2018-05-22 14:02:32 +00:00
|
|
|
|
unsigned short prevWith:14; // nr of levels up to next `with' environment
|
|
|
|
|
enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2;
|
2010-10-22 15:51:52 +00:00
|
|
|
|
Value * values[0];
|
2010-04-14 14:42:32 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2010-06-10 10:29:50 +00:00
|
|
|
|
void copyContext(const Value & v, PathSet & context);
|
|
|
|
|
|
2010-03-30 09:22:33 +00:00
|
|
|
|
|
2006-03-09 15:09:18 +00:00
|
|
|
|
/* Cache for calls to addToStore(); maps source paths to the store
|
|
|
|
|
paths. */
|
2019-12-05 18:11:09 +00:00
|
|
|
|
typedef std::map<Path, StorePath> SrcToStore;
|
2006-03-09 15:09:18 +00:00
|
|
|
|
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
2010-05-18 10:36:37 +00:00
|
|
|
|
std::ostream & operator << (std::ostream & str, const Value & v);
|
2004-02-04 16:03:29 +00:00
|
|
|
|
|
|
|
|
|
|
2016-04-14 13:32:24 +00:00
|
|
|
|
typedef std::pair<std::string, std::string> SearchPathElem;
|
|
|
|
|
typedef std::list<SearchPathElem> SearchPath;
|
2014-05-26 15:02:22 +00:00
|
|
|
|
|
|
|
|
|
|
2015-03-19 19:02:37 +00:00
|
|
|
|
/* Initialise the Boehm GC, if applicable. */
|
|
|
|
|
void initGC();
|
|
|
|
|
|
|
|
|
|
|
2020-09-21 16:22:45 +00:00
|
|
|
|
struct RegexCache;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<RegexCache> makeRegexCache();
|
|
|
|
|
|
|
|
|
|
|
2013-09-02 14:29:15 +00:00
|
|
|
|
class EvalState
|
2003-10-30 16:48:26 +00:00
|
|
|
|
{
|
2010-03-31 15:38:03 +00:00
|
|
|
|
public:
|
2010-04-13 12:25:42 +00:00
|
|
|
|
SymbolTable symbols;
|
|
|
|
|
|
2013-10-28 06:34:44 +00:00
|
|
|
|
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
|
2013-11-18 19:14:54 +00:00
|
|
|
|
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
|
2016-08-29 15:28:20 +00:00
|
|
|
|
sFile, sLine, sColumn, sFunctor, sToString,
|
2017-03-04 13:24:06 +00:00
|
|
|
|
sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
|
2020-07-22 23:59:25 +00:00
|
|
|
|
sContentAddressed,
|
2018-11-29 18:18:36 +00:00
|
|
|
|
sOutputHash, sOutputHashAlgo, sOutputHashMode,
|
2020-06-26 06:46:46 +00:00
|
|
|
|
sRecurseForDerivations,
|
2022-01-12 17:08:48 +00:00
|
|
|
|
sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath,
|
|
|
|
|
sPrefix;
|
2013-10-17 09:47:38 +00:00
|
|
|
|
Symbol sDerivationNix;
|
2010-04-13 12:25:42 +00:00
|
|
|
|
|
2012-10-03 19:09:18 +00:00
|
|
|
|
/* If set, force copying files to the Nix store even if they
|
|
|
|
|
already exist there. */
|
2017-06-28 16:11:01 +00:00
|
|
|
|
RepairFlag repair;
|
2012-10-03 19:09:18 +00:00
|
|
|
|
|
2018-01-16 17:50:38 +00:00
|
|
|
|
/* The allowed filesystem paths in restricted or pure evaluation
|
|
|
|
|
mode. */
|
2019-02-12 12:43:32 +00:00
|
|
|
|
std::optional<PathSet> allowedPaths;
|
2015-02-23 13:41:53 +00:00
|
|
|
|
|
2022-01-04 18:23:11 +00:00
|
|
|
|
Bindings emptyBindings;
|
2015-07-23 21:11:08 +00:00
|
|
|
|
|
2021-06-29 19:09:48 +00:00
|
|
|
|
/* Store used to materialise .drv files. */
|
2016-02-04 13:48:42 +00:00
|
|
|
|
const ref<Store> store;
|
Eliminate the "store" global variable
Also, move a few free-standing functions into StoreAPI and Derivation.
Also, introduce a non-nullable smart pointer, ref<T>, which is just a
wrapper around std::shared_ptr ensuring that the pointer is never
null. (For reference-counted values, this is better than passing a
"T&", because the latter doesn't maintain the refcount. Usually, the
caller will have a shared_ptr keeping the value alive, but that's not
always the case, e.g., when passing a reference to a std::thread via
std::bind.)
2016-02-04 13:28:26 +00:00
|
|
|
|
|
2021-06-29 19:09:48 +00:00
|
|
|
|
/* Store used to build stuff. */
|
|
|
|
|
const ref<Store> buildStore;
|
|
|
|
|
|
2021-08-29 16:55:38 +00:00
|
|
|
|
RootValue vCallFlake = nullptr;
|
2021-08-29 17:31:52 +00:00
|
|
|
|
RootValue vImportedDrvToDerivation = nullptr;
|
2019-03-21 08:30:16 +00:00
|
|
|
|
|
2010-03-31 15:38:03 +00:00
|
|
|
|
private:
|
2013-09-02 14:29:15 +00:00
|
|
|
|
SrcToStore srcToStore;
|
2003-10-30 16:48:26 +00:00
|
|
|
|
|
2018-06-11 14:06:01 +00:00
|
|
|
|
/* A cache from path names to parse trees. */
|
|
|
|
|
#if HAVE_BOEHMGC
|
|
|
|
|
typedef std::map<Path, Expr *, std::less<Path>, traceable_allocator<std::pair<const Path, Expr *> > > FileParseCache;
|
|
|
|
|
#else
|
|
|
|
|
typedef std::map<Path, Expr *> FileParseCache;
|
|
|
|
|
#endif
|
|
|
|
|
FileParseCache fileParseCache;
|
|
|
|
|
|
2011-08-06 19:45:43 +00:00
|
|
|
|
/* A cache from path names to values. */
|
|
|
|
|
#if HAVE_BOEHMGC
|
2014-08-20 22:05:17 +00:00
|
|
|
|
typedef std::map<Path, Value, std::less<Path>, traceable_allocator<std::pair<const Path, Value> > > FileEvalCache;
|
2011-08-06 19:45:43 +00:00
|
|
|
|
#else
|
|
|
|
|
typedef std::map<Path, Value> FileEvalCache;
|
|
|
|
|
#endif
|
|
|
|
|
FileEvalCache fileEvalCache;
|
|
|
|
|
|
2011-08-06 17:48:57 +00:00
|
|
|
|
SearchPath searchPath;
|
2011-08-06 16:05:24 +00:00
|
|
|
|
|
2016-04-14 13:32:24 +00:00
|
|
|
|
std::map<std::string, std::pair<bool, std::string>> searchPathResolved;
|
|
|
|
|
|
2018-05-22 11:02:14 +00:00
|
|
|
|
/* Cache used by checkSourcePath(). */
|
|
|
|
|
std::unordered_map<Path, Path> resolvedPaths;
|
|
|
|
|
|
2020-02-21 18:25:49 +00:00
|
|
|
|
/* Cache used by prim_match(). */
|
2020-09-21 16:22:45 +00:00
|
|
|
|
std::shared_ptr<RegexCache> regexCache;
|
2020-02-21 18:25:49 +00:00
|
|
|
|
|
2022-01-05 00:48:26 +00:00
|
|
|
|
#if HAVE_BOEHMGC
|
2021-12-20 12:28:54 +00:00
|
|
|
|
/* Allocation cache for GC'd Value objects. */
|
2022-01-22 20:17:35 +00:00
|
|
|
|
std::shared_ptr<void *> valueAllocCache;
|
2021-12-20 12:28:54 +00:00
|
|
|
|
|
2021-12-26 18:32:08 +00:00
|
|
|
|
/* Allocation cache for size-1 Env objects. */
|
|
|
|
|
std::shared_ptr<void *> env1AllocCache;
|
2022-01-05 00:48:26 +00:00
|
|
|
|
#endif
|
2021-12-26 18:32:08 +00:00
|
|
|
|
|
2010-03-30 15:18:20 +00:00
|
|
|
|
public:
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2021-06-29 19:09:48 +00:00
|
|
|
|
EvalState(
|
|
|
|
|
const Strings & _searchPath,
|
|
|
|
|
ref<Store> store,
|
|
|
|
|
std::shared_ptr<Store> buildStore = nullptr);
|
2010-04-09 12:00:49 +00:00
|
|
|
|
~EvalState();
|
2004-02-04 16:03:29 +00:00
|
|
|
|
|
2021-09-28 20:12:41 +00:00
|
|
|
|
void requireExperimentalFeatureOnEvaluation(
|
2021-10-25 13:53:01 +00:00
|
|
|
|
const ExperimentalFeature &,
|
2021-09-28 20:12:41 +00:00
|
|
|
|
const std::string_view fName,
|
|
|
|
|
const Pos & pos
|
|
|
|
|
);
|
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
void addToSearchPath(const std::string & s);
|
2011-08-06 16:05:24 +00:00
|
|
|
|
|
2016-08-23 15:11:19 +00:00
|
|
|
|
SearchPath getSearchPath() { return searchPath; }
|
|
|
|
|
|
2021-10-07 10:11:00 +00:00
|
|
|
|
/* Allow access to a path. */
|
|
|
|
|
void allowPath(const Path & path);
|
|
|
|
|
|
2021-10-07 12:07:51 +00:00
|
|
|
|
/* Allow access to a store path. Note that this gets remapped to
|
|
|
|
|
the real store path if `store` is a chroot store. */
|
|
|
|
|
void allowPath(const StorePath & storePath);
|
|
|
|
|
|
2022-02-27 14:59:34 +00:00
|
|
|
|
/* Allow access to a store path and return it as a string. */
|
2022-03-01 10:29:19 +00:00
|
|
|
|
void allowAndSetStorePathString(const StorePath & storePath, Value & v);
|
2022-02-27 14:59:34 +00:00
|
|
|
|
|
2021-10-07 10:11:00 +00:00
|
|
|
|
/* Check whether access to a path is allowed and throw an error if
|
|
|
|
|
not. Otherwise return the canonicalised path. */
|
2015-02-23 13:41:53 +00:00
|
|
|
|
Path checkSourcePath(const Path & path);
|
|
|
|
|
|
2017-10-30 11:39:59 +00:00
|
|
|
|
void checkURI(const std::string & uri);
|
|
|
|
|
|
2018-01-12 16:31:08 +00:00
|
|
|
|
/* When using a diverted store and 'path' is in the Nix store, map
|
|
|
|
|
'path' to the diverted location (e.g. /nix/store/foo is mapped
|
|
|
|
|
to /home/alice/my-nix/nix/store/foo). However, this is only
|
|
|
|
|
done if the context is not empty, since otherwise we're
|
|
|
|
|
probably trying to read from the actual /nix/store. This is
|
|
|
|
|
intended to distinguish between import-from-derivation and
|
|
|
|
|
sources stored in the actual /nix/store. */
|
|
|
|
|
Path toRealPath(const Path & path, const PathSet & context);
|
|
|
|
|
|
2013-09-03 10:56:33 +00:00
|
|
|
|
/* Parse a Nix expression from the specified file. */
|
|
|
|
|
Expr * parseExprFromFile(const Path & path);
|
Add primop ‘scopedImport’
‘scopedImport’ works like ‘import’, except that it takes a set of
attributes to be added to the lexical scope of the expression,
essentially extending or overriding the builtin variables. For
instance, the expression
scopedImport { x = 1; } ./foo.nix
where foo.nix contains ‘x’, will evaluate to 1.
This has a few applications:
* It allows getting rid of function argument specifications in package
expressions. For instance, a package expression like:
{ stdenv, fetchurl, libfoo }:
stdenv.mkDerivation { ... buildInputs = [ libfoo ]; }
can now we written as just
stdenv.mkDerivation { ... buildInputs = [ libfoo ]; }
and imported in all-packages.nix as:
bar = scopedImport pkgs ./bar.nix;
So whereas we once had dependencies listed in three places
(buildInputs, the function, and the call site), they now only need
to appear in one place.
* It allows overriding builtin functions. For instance, to trace all
calls to ‘map’:
let
overrides = {
map = f: xs: builtins.trace "map called!" (map f xs);
# Ensure that our override gets propagated by calls to
# import/scopedImport.
import = fn: scopedImport overrides fn;
scopedImport = attrs: fn: scopedImport (overrides // attrs) fn;
# Also update ‘builtins’.
builtins = builtins // overrides;
};
in scopedImport overrides ./bla.nix
* Similarly, it allows extending the set of builtin functions. For
instance, during Nixpkgs/NixOS evaluation, the Nixpkgs library
functions could be added to the default scope.
There is a downside: calls to scopedImport are not memoized, unlike
import. So importing a file multiple times leads to multiple parsings
/ evaluations. It would be possible to construct the AST only once,
but that would require careful handling of variables/environments.
2014-05-26 11:46:11 +00:00
|
|
|
|
Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv);
|
2011-08-06 13:02:55 +00:00
|
|
|
|
|
|
|
|
|
/* Parse a Nix expression from the specified string. */
|
2021-12-21 12:56:57 +00:00
|
|
|
|
Expr * parseExprFromString(std::string s, const Path & basePath, StaticEnv & staticEnv);
|
|
|
|
|
Expr * parseExprFromString(std::string s, const Path & basePath);
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2017-07-25 13:09:06 +00:00
|
|
|
|
Expr * parseStdin();
|
|
|
|
|
|
2010-03-30 09:22:33 +00:00
|
|
|
|
/* Evaluate an expression read from the given file to normal
|
2019-09-09 15:34:38 +00:00
|
|
|
|
form. Optionally enforce that the top-level expression is
|
|
|
|
|
trivial (i.e. doesn't require arbitrary computation). */
|
|
|
|
|
void evalFile(const Path & path, Value & v, bool mustBeTrivial = false);
|
2010-03-30 09:22:33 +00:00
|
|
|
|
|
2021-09-13 12:41:28 +00:00
|
|
|
|
/* Like `cacheFile`, but with an already parsed expression. */
|
|
|
|
|
void cacheFile(
|
|
|
|
|
const Path & path,
|
|
|
|
|
const Path & resolvedPath,
|
|
|
|
|
Expr * e,
|
|
|
|
|
Value & v,
|
|
|
|
|
bool mustBeTrivial = false);
|
|
|
|
|
|
2013-09-02 16:34:04 +00:00
|
|
|
|
void resetFileCache();
|
|
|
|
|
|
2011-08-06 16:05:24 +00:00
|
|
|
|
/* Look up a file in the search path. */
|
2022-01-21 13:44:00 +00:00
|
|
|
|
Path findFile(const std::string_view path);
|
|
|
|
|
Path findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos = noPos);
|
2011-08-06 16:05:24 +00:00
|
|
|
|
|
2016-04-14 13:32:24 +00:00
|
|
|
|
/* If the specified search path element is a URI, download it. */
|
|
|
|
|
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
|
|
|
|
|
|
2010-03-29 14:37:56 +00:00
|
|
|
|
/* Evaluate an expression to normal form, storing the result in
|
|
|
|
|
value `v'. */
|
2010-04-12 18:30:11 +00:00
|
|
|
|
void eval(Expr * e, Value & v);
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
|
|
|
|
/* Evaluation the expression, then verify that it has the expected
|
|
|
|
|
type. */
|
2012-02-04 13:50:25 +00:00
|
|
|
|
inline bool evalBool(Env & env, Expr * e);
|
2014-04-04 20:43:52 +00:00
|
|
|
|
inline bool evalBool(Env & env, Expr * e, const Pos & pos);
|
2012-02-04 13:50:25 +00:00
|
|
|
|
inline void evalAttrs(Env & env, Expr * e, Value & v);
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
|
|
|
|
/* If `v' is a thunk, enter it and overwrite `v' with the result
|
2010-03-30 13:47:59 +00:00
|
|
|
|
of the evaluation of the thunk. If `v' is a delayed function
|
|
|
|
|
application, call the function and overwrite `v' with the
|
|
|
|
|
result. Otherwise, this is a no-op. */
|
2021-11-27 17:40:24 +00:00
|
|
|
|
inline void forceValue(Value & v, const Pos & pos);
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
2022-02-03 23:31:33 +00:00
|
|
|
|
template <typename Callable>
|
|
|
|
|
inline void forceValue(Value & v, Callable getPos);
|
|
|
|
|
|
2010-04-07 13:55:46 +00:00
|
|
|
|
/* Force a value, then recursively force list elements and
|
|
|
|
|
attributes. */
|
2014-09-22 13:03:59 +00:00
|
|
|
|
void forceValueDeep(Value & v);
|
2010-04-07 13:55:46 +00:00
|
|
|
|
|
2010-03-29 14:37:56 +00:00
|
|
|
|
/* Force `v', and then verify that it has the expected type. */
|
2014-04-04 16:58:15 +00:00
|
|
|
|
NixInt forceInt(Value & v, const Pos & pos);
|
2016-01-04 23:40:40 +00:00
|
|
|
|
NixFloat forceFloat(Value & v, const Pos & pos);
|
2016-08-29 15:56:35 +00:00
|
|
|
|
bool forceBool(Value & v, const Pos & pos);
|
2022-02-03 23:31:33 +00:00
|
|
|
|
|
|
|
|
|
void forceAttrs(Value & v, const Pos & pos);
|
|
|
|
|
|
|
|
|
|
template <typename Callable>
|
|
|
|
|
inline void forceAttrs(Value & v, Callable getPos);
|
|
|
|
|
|
2014-04-04 17:05:36 +00:00
|
|
|
|
inline void forceList(Value & v, const Pos & pos);
|
|
|
|
|
void forceFunction(Value & v, const Pos & pos); // either lambda or primop
|
2022-01-21 13:44:00 +00:00
|
|
|
|
std::string_view forceString(Value & v, const Pos & pos = noPos);
|
|
|
|
|
std::string_view forceString(Value & v, PathSet & context, const Pos & pos = noPos);
|
|
|
|
|
std::string_view forceStringNoCtx(Value & v, const Pos & pos = noPos);
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
2010-04-07 13:55:46 +00:00
|
|
|
|
/* Return true iff the value `v' denotes a derivation (i.e. a
|
|
|
|
|
set with attribute `type = "derivation"'). */
|
|
|
|
|
bool isDerivation(Value & v);
|
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
std::optional<std::string> tryAttrsToString(const Pos & pos, Value & v,
|
2019-10-27 09:15:51 +00:00
|
|
|
|
PathSet & context, bool coerceMore = false, bool copyToStore = true);
|
|
|
|
|
|
2010-03-30 09:22:33 +00:00
|
|
|
|
/* String coercion. Converts strings, paths and derivations to a
|
|
|
|
|
string. If `coerceMore' is set, also converts nulls, integers,
|
|
|
|
|
booleans and lists to a string. If `copyToStore' is set,
|
2013-08-14 20:32:49 +00:00
|
|
|
|
referenced paths are copied to the Nix store as a side effect. */
|
2022-01-21 15:20:54 +00:00
|
|
|
|
BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
|
2021-07-29 16:03:07 +00:00
|
|
|
|
bool coerceMore = false, bool copyToStore = true,
|
2021-08-31 12:02:04 +00:00
|
|
|
|
bool canonicalizePath = true);
|
2010-03-30 09:22:33 +00:00
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
std::string copyPathToStore(PathSet & context, const Path & path);
|
2013-11-18 23:03:11 +00:00
|
|
|
|
|
2010-03-30 09:22:33 +00:00
|
|
|
|
/* Path coercion. Converts strings, paths and derivations to a
|
|
|
|
|
path. The result is guaranteed to be a canonicalised, absolute
|
|
|
|
|
path. Nothing is copied to the store. */
|
2014-04-04 20:19:33 +00:00
|
|
|
|
Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
|
2010-03-30 09:22:33 +00:00
|
|
|
|
|
2022-03-02 09:57:19 +00:00
|
|
|
|
/* Like coerceToPath, but the result must be a store path. */
|
|
|
|
|
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);
|
|
|
|
|
|
2013-09-02 16:34:04 +00:00
|
|
|
|
public:
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
|
|
|
|
/* The base environment, containing the builtin functions and
|
|
|
|
|
values. */
|
|
|
|
|
Env & baseEnv;
|
|
|
|
|
|
2010-04-14 22:59:39 +00:00
|
|
|
|
/* The same, but used during parsing to resolve variables. */
|
|
|
|
|
StaticEnv staticBaseEnv; // !!! should be private
|
|
|
|
|
|
|
|
|
|
private:
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2015-07-23 21:14:07 +00:00
|
|
|
|
unsigned int baseEnvDispl = 0;
|
2013-09-02 16:34:04 +00:00
|
|
|
|
|
2010-03-29 14:37:56 +00:00
|
|
|
|
void createBaseEnv();
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
Value * addConstant(const std::string & name, Value & v);
|
2010-03-30 14:39:27 +00:00
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
void addConstant(const std::string & name, Value * v);
|
2020-03-02 17:15:06 +00:00
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
Value * addPrimOp(const std::string & name,
|
2018-05-02 11:56:34 +00:00
|
|
|
|
size_t arity, PrimOpFun primOp);
|
2010-03-29 14:37:56 +00:00
|
|
|
|
|
2020-08-24 11:11:56 +00:00
|
|
|
|
Value * addPrimOp(PrimOp && primOp);
|
|
|
|
|
|
2013-09-03 13:45:32 +00:00
|
|
|
|
public:
|
|
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
|
Value & getBuiltin(const std::string & name);
|
2013-09-03 13:45:32 +00:00
|
|
|
|
|
2020-08-25 11:31:11 +00:00
|
|
|
|
struct Doc
|
|
|
|
|
{
|
|
|
|
|
Pos pos;
|
|
|
|
|
std::optional<Symbol> name;
|
|
|
|
|
size_t arity;
|
|
|
|
|
std::vector<std::string> args;
|
|
|
|
|
const char * doc;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::optional<Doc> getDoc(Value & v);
|
|
|
|
|
|
2013-09-03 13:45:32 +00:00
|
|
|
|
private:
|
|
|
|
|
|
2013-10-08 12:24:53 +00:00
|
|
|
|
inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2014-01-21 17:29:55 +00:00
|
|
|
|
friend struct ExprVar;
|
|
|
|
|
friend struct ExprAttrs;
|
|
|
|
|
friend struct ExprLet;
|
2010-04-13 12:25:42 +00:00
|
|
|
|
|
2022-01-21 16:55:51 +00:00
|
|
|
|
Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path,
|
|
|
|
|
const PathView basePath, StaticEnv & staticEnv);
|
2011-08-06 13:02:55 +00:00
|
|
|
|
|
2010-04-12 18:30:11 +00:00
|
|
|
|
public:
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2010-03-29 14:37:56 +00:00
|
|
|
|
/* Do a deep equality test between two values. That is, list
|
|
|
|
|
elements and attributes are compared recursively. */
|
|
|
|
|
bool eqValues(Value & v1, Value & v2);
|
|
|
|
|
|
2015-09-06 23:03:23 +00:00
|
|
|
|
bool isFunctor(Value & fun);
|
|
|
|
|
|
2020-02-24 00:32:01 +00:00
|
|
|
|
// FIXME: use std::span
|
|
|
|
|
void callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos);
|
|
|
|
|
|
|
|
|
|
void callFunction(Value & fun, Value & arg, Value & vRes, const Pos & pos)
|
|
|
|
|
{
|
|
|
|
|
Value * args[] = {&arg};
|
|
|
|
|
callFunction(fun, 1, args, vRes, pos);
|
|
|
|
|
}
|
2010-04-07 13:55:46 +00:00
|
|
|
|
|
2010-04-07 15:47:06 +00:00
|
|
|
|
/* Automatically call a function for which each argument has a
|
|
|
|
|
default value or has a binding in the `args' map. */
|
2010-10-22 14:47:42 +00:00
|
|
|
|
void autoCallFunction(Bindings & args, Value & fun, Value & res);
|
2013-09-02 14:29:15 +00:00
|
|
|
|
|
2010-03-29 14:37:56 +00:00
|
|
|
|
/* Allocation primitives. */
|
2021-12-28 18:18:17 +00:00
|
|
|
|
inline Value * allocValue();
|
|
|
|
|
inline Env & allocEnv(size_t size);
|
2010-03-30 14:39:27 +00:00
|
|
|
|
|
2010-10-22 14:47:42 +00:00
|
|
|
|
Value * allocAttr(Value & vAttrs, const Symbol & name);
|
2022-01-04 16:39:16 +00:00
|
|
|
|
Value * allocAttr(Value & vAttrs, std::string_view name);
|
2010-10-22 14:47:42 +00:00
|
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
|
Bindings * allocBindings(size_t capacity);
|
2014-09-19 14:49:41 +00:00
|
|
|
|
|
2022-01-04 16:39:16 +00:00
|
|
|
|
BindingsBuilder buildBindings(size_t capacity)
|
|
|
|
|
{
|
|
|
|
|
return BindingsBuilder(*this, allocBindings(capacity));
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
|
void mkList(Value & v, size_t length);
|
2010-04-12 18:30:11 +00:00
|
|
|
|
void mkThunk_(Value & v, Expr * expr);
|
2021-08-29 16:09:13 +00:00
|
|
|
|
void mkPos(Value & v, ptr<Pos> pos);
|
2010-10-24 14:20:02 +00:00
|
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
|
void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos);
|
2012-08-13 05:53:10 +00:00
|
|
|
|
|
2010-03-30 15:18:20 +00:00
|
|
|
|
/* Print statistics. */
|
|
|
|
|
void printStats();
|
2010-04-09 12:00:49 +00:00
|
|
|
|
|
2021-12-20 18:46:55 +00:00
|
|
|
|
/* Realise the given context, and return a mapping from the placeholders
|
|
|
|
|
* used to construct the associated value to their final store path
|
|
|
|
|
*/
|
|
|
|
|
[[nodiscard]] StringMap realiseContext(const PathSet & context);
|
Eliminate the "store" global variable
Also, move a few free-standing functions into StoreAPI and Derivation.
Also, introduce a non-nullable smart pointer, ref<T>, which is just a
wrapper around std::shared_ptr ensuring that the pointer is never
null. (For reference-counted values, this is better than passing a
"T&", because the latter doesn't maintain the refcount. Usually, the
caller will have a shared_ptr keeping the value alive, but that's not
always the case, e.g., when passing a reference to a std::thread via
std::bind.)
2016-02-04 13:28:26 +00:00
|
|
|
|
|
2010-04-09 12:00:49 +00:00
|
|
|
|
private:
|
2012-08-13 03:41:48 +00:00
|
|
|
|
|
2015-07-23 21:14:07 +00:00
|
|
|
|
unsigned long nrEnvs = 0;
|
|
|
|
|
unsigned long nrValuesInEnvs = 0;
|
|
|
|
|
unsigned long nrValues = 0;
|
|
|
|
|
unsigned long nrListElems = 0;
|
2021-07-21 22:31:08 +00:00
|
|
|
|
unsigned long nrLookups = 0;
|
2015-07-23 21:14:07 +00:00
|
|
|
|
unsigned long nrAttrsets = 0;
|
|
|
|
|
unsigned long nrAttrsInAttrsets = 0;
|
2021-07-21 22:31:08 +00:00
|
|
|
|
unsigned long nrAvoided = 0;
|
2015-07-23 21:14:07 +00:00
|
|
|
|
unsigned long nrOpUpdates = 0;
|
|
|
|
|
unsigned long nrOpUpdateValuesCopied = 0;
|
|
|
|
|
unsigned long nrListConcats = 0;
|
|
|
|
|
unsigned long nrPrimOpCalls = 0;
|
|
|
|
|
unsigned long nrFunctionCalls = 0;
|
2012-08-13 03:29:28 +00:00
|
|
|
|
|
|
|
|
|
bool countCalls;
|
|
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
|
typedef std::map<Symbol, size_t> PrimOpCalls;
|
2012-08-13 03:29:28 +00:00
|
|
|
|
PrimOpCalls primOpCalls;
|
|
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
|
typedef std::map<ExprLambda *, size_t> FunctionCalls;
|
2012-08-13 03:29:28 +00:00
|
|
|
|
FunctionCalls functionCalls;
|
|
|
|
|
|
2013-11-07 17:04:36 +00:00
|
|
|
|
void incrFunctionCall(ExprLambda * fun);
|
|
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
|
typedef std::map<Pos, size_t> AttrSelects;
|
2012-08-13 03:29:28 +00:00
|
|
|
|
AttrSelects attrSelects;
|
|
|
|
|
|
2014-01-21 17:29:55 +00:00
|
|
|
|
friend struct ExprOpUpdate;
|
|
|
|
|
friend struct ExprOpConcatLists;
|
2021-07-21 22:31:08 +00:00
|
|
|
|
friend struct ExprVar;
|
|
|
|
|
friend struct ExprString;
|
|
|
|
|
friend struct ExprInt;
|
|
|
|
|
friend struct ExprFloat;
|
|
|
|
|
friend struct ExprPath;
|
2014-01-21 17:29:55 +00:00
|
|
|
|
friend struct ExprSelect;
|
2014-04-04 16:51:01 +00:00
|
|
|
|
friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v);
|
2020-02-21 18:25:49 +00:00
|
|
|
|
friend void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v);
|
2022-01-01 23:46:43 +00:00
|
|
|
|
friend void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v);
|
2022-01-04 19:29:17 +00:00
|
|
|
|
|
|
|
|
|
friend struct Value;
|
2003-10-30 16:48:26 +00:00
|
|
|
|
};
|
2010-04-07 13:55:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a string representing the type of the value `v'. */
|
2022-02-25 15:00:00 +00:00
|
|
|
|
std::string_view showType(ValueType type);
|
|
|
|
|
std::string showType(const Value & v);
|
2003-10-30 16:48:26 +00:00
|
|
|
|
|
2019-01-13 17:43:46 +00:00
|
|
|
|
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
|
|
|
|
name>. */
|
2022-03-12 00:28:00 +00:00
|
|
|
|
NixStringContextElem decodeContext(const Store & store, std::string_view s);
|
2003-10-30 16:48:26 +00:00
|
|
|
|
|
2013-09-03 10:56:33 +00:00
|
|
|
|
/* If `path' refers to a directory, then append "/default.nix". */
|
|
|
|
|
Path resolveExprPath(Path path);
|
|
|
|
|
|
2014-10-18 02:15:09 +00:00
|
|
|
|
struct InvalidPathError : EvalError
|
|
|
|
|
{
|
|
|
|
|
Path path;
|
|
|
|
|
InvalidPathError(const Path & path);
|
2014-10-20 16:15:50 +00:00
|
|
|
|
#ifdef EXCEPTION_NEEDS_THROW_SPEC
|
|
|
|
|
~InvalidPathError() throw () { };
|
|
|
|
|
#endif
|
2014-10-18 02:15:09 +00:00
|
|
|
|
};
|
|
|
|
|
|
2018-03-27 17:02:22 +00:00
|
|
|
|
struct EvalSettings : Config
|
|
|
|
|
{
|
2019-11-22 22:07:35 +00:00
|
|
|
|
EvalSettings();
|
|
|
|
|
|
|
|
|
|
static Strings getDefaultNixPath();
|
|
|
|
|
|
2018-03-27 17:02:22 +00:00
|
|
|
|
Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation",
|
|
|
|
|
"Whether builtin functions that allow executing native code should be enabled."};
|
|
|
|
|
|
2020-08-19 16:28:04 +00:00
|
|
|
|
Setting<Strings> nixPath{
|
|
|
|
|
this, getDefaultNixPath(), "nix-path",
|
|
|
|
|
"List of directories to be searched for `<...>` file references."};
|
|
|
|
|
|
|
|
|
|
Setting<bool> restrictEval{
|
|
|
|
|
this, false, "restrict-eval",
|
|
|
|
|
R"(
|
|
|
|
|
If set to `true`, the Nix evaluator will not allow access to any
|
|
|
|
|
files outside of the Nix search path (as set via the `NIX_PATH`
|
|
|
|
|
environment variable or the `-I` option), or to URIs outside of
|
|
|
|
|
`allowed-uri`. The default is `false`.
|
|
|
|
|
)"};
|
2018-03-27 17:02:22 +00:00
|
|
|
|
|
|
|
|
|
Setting<bool> pureEval{this, false, "pure-eval",
|
|
|
|
|
"Whether to restrict file system and network access to files specified by cryptographic hash."};
|
|
|
|
|
|
2020-08-19 16:28:04 +00:00
|
|
|
|
Setting<bool> enableImportFromDerivation{
|
|
|
|
|
this, true, "allow-import-from-derivation",
|
|
|
|
|
R"(
|
|
|
|
|
By default, Nix allows you to `import` from a derivation, allowing
|
|
|
|
|
building at evaluation time. With this option set to false, Nix will
|
|
|
|
|
throw an error when evaluating an expression that uses this feature,
|
|
|
|
|
allowing users to ensure their evaluation will not require any
|
|
|
|
|
builds to take place.
|
|
|
|
|
)"};
|
2018-03-27 17:02:22 +00:00
|
|
|
|
|
|
|
|
|
Setting<Strings> allowedUris{this, {}, "allowed-uris",
|
2020-08-19 16:28:04 +00:00
|
|
|
|
R"(
|
|
|
|
|
A list of URI prefixes to which access is allowed in restricted
|
|
|
|
|
evaluation mode. For example, when set to
|
|
|
|
|
`https://github.com/NixOS`, builtin functions such as `fetchGit` are
|
|
|
|
|
allowed to access `https://github.com/NixOS/patchelf.git`.
|
|
|
|
|
)"};
|
2019-05-07 20:29:16 +00:00
|
|
|
|
|
2019-04-12 16:31:33 +00:00
|
|
|
|
Setting<bool> traceFunctionCalls{this, false, "trace-function-calls",
|
2020-08-19 16:28:04 +00:00
|
|
|
|
R"(
|
|
|
|
|
If set to `true`, the Nix evaluator will trace every function call.
|
|
|
|
|
Nix will print a log message at the "vomit" level for every function
|
|
|
|
|
entrance and function exit.
|
|
|
|
|
|
|
|
|
|
function-trace entered undefined position at 1565795816999559622
|
|
|
|
|
function-trace exited undefined position at 1565795816999581277
|
|
|
|
|
function-trace entered /nix/store/.../example.nix:226:41 at 1565795253249935150
|
|
|
|
|
function-trace exited /nix/store/.../example.nix:226:41 at 1565795253249941684
|
|
|
|
|
|
|
|
|
|
The `undefined position` means the function call is a builtin.
|
|
|
|
|
|
|
|
|
|
Use the `contrib/stack-collapse.py` script distributed with the Nix
|
|
|
|
|
source code to convert the trace logs in to a format suitable for
|
|
|
|
|
`flamegraph.pl`.
|
|
|
|
|
)"};
|
2020-08-07 12:13:24 +00:00
|
|
|
|
|
|
|
|
|
Setting<bool> useEvalCache{this, true, "eval-cache",
|
|
|
|
|
"Whether to use the flake evaluation cache."};
|
2018-03-27 17:02:22 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern EvalSettings evalSettings;
|
|
|
|
|
|
2020-12-22 13:43:20 +00:00
|
|
|
|
static const std::string corepkgsPrefix{"/__corepkgs__/"};
|
|
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
|
}
|
2021-12-28 18:18:17 +00:00
|
|
|
|
|
|
|
|
|
#include "eval-inline.hh"
|