about summary refs log tree commit diff
path: root/third_party/nix/src/libexpr/eval.hh
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/nix/src/libexpr/eval.hh')
-rw-r--r--third_party/nix/src/libexpr/eval.hh510
1 files changed, 252 insertions, 258 deletions
diff --git a/third_party/nix/src/libexpr/eval.hh b/third_party/nix/src/libexpr/eval.hh
index 8126e4ea50..74777e48fa 100644
--- a/third_party/nix/src/libexpr/eval.hh
+++ b/third_party/nix/src/libexpr/eval.hh
@@ -1,363 +1,357 @@
 #pragma once
 
-#include "attr-set.hh"
-#include "value.hh"
-#include "nixexpr.hh"
-#include "symbol-table.hh"
-#include "hash.hh"
-#include "config.hh"
-
 #include <map>
 #include <optional>
 #include <unordered_map>
-
+#include "attr-set.hh"
+#include "config.hh"
+#include "hash.hh"
+#include "nixexpr.hh"
+#include "symbol-table.hh"
+#include "value.hh"
 
 namespace nix {
 
-
 class Store;
 class EvalState;
 enum RepairFlag : bool;
 
+typedef void (*PrimOpFun)(EvalState& state, const Pos& pos, Value** args,
+                          Value& v);
 
-typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v);
-
-
-struct PrimOp
-{
-    PrimOpFun fun;
-    size_t arity;
-    Symbol name;
-    PrimOp(PrimOpFun fun, size_t arity, Symbol name)
-        : fun(fun), arity(arity), name(name) { }
+struct PrimOp {
+  PrimOpFun fun;
+  size_t arity;
+  Symbol name;
+  PrimOp(PrimOpFun fun, size_t arity, Symbol name)
+      : fun(fun), arity(arity), name(name) {}
 };
 
-
-struct Env
-{
-    Env * up;
-    unsigned short size; // used by ‘valueSize’
-    unsigned short prevWith:14; // nr of levels up to next `with' environment
-    enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2;
-    Value * values[0];
+struct Env {
+  Env* up;
+  unsigned short size;           // used by ‘valueSize’
+  unsigned short prevWith : 14;  // nr of levels up to next `with' environment
+  enum { Plain = 0, HasWithExpr, HasWithAttrs } type : 2;
+  Value* values[0];
 };
 
+Value& 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);
-
+void copyContext(const Value& v, PathSet& context);
 
 /* Cache for calls to addToStore(); maps source paths to the store
    paths. */
 typedef std::map<Path, Path> SrcToStore;
 
-
-std::ostream & operator << (std::ostream & str, const Value & v);
-
+std::ostream& operator<<(std::ostream& str, const Value& v);
 
 typedef std::pair<std::string, std::string> SearchPathElem;
 typedef std::list<SearchPathElem> SearchPath;
 
-
 /* Initialise the Boehm GC, if applicable. */
 void initGC();
 
+class EvalState {
+ public:
+  SymbolTable symbols;
 
-class EvalState
-{
-public:
-    SymbolTable symbols;
-
-    const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
-        sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
-        sFile, sLine, sColumn, sFunctor, sToString,
-        sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
-        sOutputHash, sOutputHashAlgo, sOutputHashMode;
-    Symbol sDerivationNix;
+  const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem,
+      sOverrides, sOutputs, sOutputName, sIgnoreNulls, sFile, sLine, sColumn,
+      sFunctor, sToString, sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
+      sOutputHash, sOutputHashAlgo, sOutputHashMode;
+  Symbol sDerivationNix;
 
-    /* If set, force copying files to the Nix store even if they
-       already exist there. */
-    RepairFlag repair;
+  /* If set, force copying files to the Nix store even if they
+     already exist there. */
+  RepairFlag repair;
 
-    /* The allowed filesystem paths in restricted or pure evaluation
-       mode. */
-    std::optional<PathSet> allowedPaths;
+  /* The allowed filesystem paths in restricted or pure evaluation
+     mode. */
+  std::optional<PathSet> allowedPaths;
 
-    Value vEmptySet;
+  Value vEmptySet;
 
-    const ref<Store> store;
+  const ref<Store> store;
 
-private:
-    SrcToStore srcToStore;
+ private:
+  SrcToStore srcToStore;
 
-    /* A cache from path names to parse trees. */
+  /* 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;
+  typedef std::map<Path, Expr*, std::less<Path>,
+                   traceable_allocator<std::pair<const Path, Expr*>>>
+      FileParseCache;
 #else
-    typedef std::map<Path, Expr *> FileParseCache;
+  typedef std::map<Path, Expr*> FileParseCache;
 #endif
-    FileParseCache fileParseCache;
+  FileParseCache fileParseCache;
 
-    /* A cache from path names to values. */
+  /* A cache from path names to values. */
 #if HAVE_BOEHMGC
-    typedef std::map<Path, Value, std::less<Path>, traceable_allocator<std::pair<const Path, Value> > > FileEvalCache;
+  typedef std::map<Path, Value, std::less<Path>,
+                   traceable_allocator<std::pair<const Path, Value>>>
+      FileEvalCache;
 #else
-    typedef std::map<Path, Value> FileEvalCache;
+  typedef std::map<Path, Value> FileEvalCache;
 #endif
-    FileEvalCache fileEvalCache;
+  FileEvalCache fileEvalCache;
+
+  SearchPath searchPath;
+
+  std::map<std::string, std::pair<bool, std::string>> searchPathResolved;
+
+  /* Cache used by checkSourcePath(). */
+  std::unordered_map<Path, Path> resolvedPaths;
+
+ public:
+  EvalState(const Strings& _searchPath, ref<Store> store);
+  ~EvalState();
+
+  void addToSearchPath(const string& s);
+
+  SearchPath getSearchPath() { return searchPath; }
+
+  Path checkSourcePath(const Path& path);
+
+  void checkURI(const std::string& uri);
+
+  /* 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);
 
-    SearchPath searchPath;
+  /* Parse a Nix expression from the specified file. */
+  Expr* parseExprFromFile(const Path& path);
+  Expr* parseExprFromFile(const Path& path, StaticEnv& staticEnv);
 
-    std::map<std::string, std::pair<bool, std::string>> searchPathResolved;
+  /* Parse a Nix expression from the specified string. */
+  Expr* parseExprFromString(const string& s, const Path& basePath,
+                            StaticEnv& staticEnv);
+  Expr* parseExprFromString(const string& s, const Path& basePath);
 
-    /* Cache used by checkSourcePath(). */
-    std::unordered_map<Path, Path> resolvedPaths;
+  Expr* parseStdin();
 
-public:
+  /* Evaluate an expression read from the given file to normal
+     form. */
+  void evalFile(const Path& path, Value& v);
 
-    EvalState(const Strings & _searchPath, ref<Store> store);
-    ~EvalState();
+  void resetFileCache();
 
-    void addToSearchPath(const string & s);
+  /* Look up a file in the search path. */
+  Path findFile(const string& path);
+  Path findFile(SearchPath& searchPath, const string& path,
+                const Pos& pos = noPos);
 
-    SearchPath getSearchPath() { return searchPath; }
+  /* If the specified search path element is a URI, download it. */
+  std::pair<bool, std::string> resolveSearchPathElem(
+      const SearchPathElem& elem);
 
-    Path checkSourcePath(const Path & path);
+  /* Evaluate an expression to normal form, storing the result in
+     value `v'. */
+  void eval(Expr* e, Value& v);
 
-    void checkURI(const std::string & uri);
+  /* Evaluation the expression, then verify that it has the expected
+     type. */
+  inline bool evalBool(Env& env, Expr* e);
+  inline bool evalBool(Env& env, Expr* e, const Pos& pos);
+  inline void evalAttrs(Env& env, Expr* e, Value& v);
 
-    /* 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);
+  /* If `v' is a thunk, enter it and overwrite `v' with the result
+     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. */
+  inline void forceValue(Value& v, const Pos& pos = noPos);
 
-    /* Parse a Nix expression from the specified file. */
-    Expr * parseExprFromFile(const Path & path);
-    Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv);
+  /* Force a value, then recursively force list elements and
+     attributes. */
+  void forceValueDeep(Value& v);
 
-    /* Parse a Nix expression from the specified string. */
-    Expr * parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv);
-    Expr * parseExprFromString(const string & s, const Path & basePath);
+  /* 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, const Pos& pos);
+  inline void forceAttrs(Value& v);
+  inline void forceAttrs(Value& v, const Pos& pos);
+  inline void forceList(Value& v);
+  inline void forceList(Value& v, const Pos& pos);
+  void forceFunction(Value& v, const Pos& pos);  // either lambda or primop
+  string forceString(Value& v, const Pos& pos = noPos);
+  string forceString(Value& v, PathSet& context, const Pos& pos = noPos);
+  string forceStringNoCtx(Value& v, const Pos& pos = noPos);
 
-    Expr * parseStdin();
+  /* Return true iff the value `v' denotes a derivation (i.e. a
+     set with attribute `type = "derivation"'). */
+  bool isDerivation(Value& v);
 
-    /* Evaluate an expression read from the given file to normal
-       form. */
-    void evalFile(const Path & path, Value & v);
+  std::optional<string> tryAttrsToString(const Pos& pos, Value& v,
+                                         PathSet& context,
+                                         bool coerceMore = false,
+                                         bool copyToStore = true);
 
-    void resetFileCache();
+  /* 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,
+     referenced paths are copied to the Nix store as a side effect. */
+  string coerceToString(const Pos& pos, Value& v, PathSet& context,
+                        bool coerceMore = false, bool copyToStore = true);
 
-    /* Look up a file in the search path. */
-    Path findFile(const string & path);
-    Path findFile(SearchPath & searchPath, const string & path, const Pos & pos = noPos);
+  string copyPathToStore(PathSet& context, const Path& path);
 
-    /* If the specified search path element is a URI, download it. */
-    std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
+  /* 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. */
+  Path coerceToPath(const Pos& pos, Value& v, PathSet& context);
 
-    /* Evaluate an expression to normal form, storing the result in
-       value `v'. */
-    void eval(Expr * e, Value & v);
+ public:
+  /* The base environment, containing the builtin functions and
+     values. */
+  Env& baseEnv;
 
-    /* Evaluation the expression, then verify that it has the expected
-       type. */
-    inline bool evalBool(Env & env, Expr * e);
-    inline bool evalBool(Env & env, Expr * e, const Pos & pos);
-    inline void evalAttrs(Env & env, Expr * e, Value & v);
+  /* The same, but used during parsing to resolve variables. */
+  StaticEnv staticBaseEnv;  // !!! should be private
+
+ private:
+  unsigned int baseEnvDispl = 0;
+
+  void createBaseEnv();
 
-    /* If `v' is a thunk, enter it and overwrite `v' with the result
-       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. */
-    inline void forceValue(Value & v, const Pos & pos = noPos);
+  Value* addConstant(const string& name, Value& v);
 
-    /* Force a value, then recursively force list elements and
-       attributes. */
-    void forceValueDeep(Value & v);
+  Value* addPrimOp(const string& name, size_t arity, PrimOpFun primOp);
 
-    /* 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, const Pos & pos);
-    inline void forceAttrs(Value & v);
-    inline void forceAttrs(Value & v, const Pos & pos);
-    inline void forceList(Value & v);
-    inline void forceList(Value & v, const Pos & pos);
-    void forceFunction(Value & v, const Pos & pos); // either lambda or primop
-    string forceString(Value & v, const Pos & pos = noPos);
-    string forceString(Value & v, PathSet & context, const Pos & pos = noPos);
-    string forceStringNoCtx(Value & v, const Pos & pos = noPos);
+ public:
+  Value& getBuiltin(const string& name);
 
-    /* Return true iff the value `v' denotes a derivation (i.e. a
-       set with attribute `type = "derivation"'). */
-    bool isDerivation(Value & v);
+ private:
+  inline Value* lookupVar(Env* env, const ExprVar& var, bool noEval);
 
-    std::optional<string> tryAttrsToString(const Pos & pos, Value & v,
-        PathSet & context, bool coerceMore = false, bool copyToStore = true);
+  friend struct ExprVar;
+  friend struct ExprAttrs;
+  friend struct ExprLet;
 
-    /* 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,
-       referenced paths are copied to the Nix store as a side effect. */
-    string coerceToString(const Pos & pos, Value & v, PathSet & context,
-        bool coerceMore = false, bool copyToStore = true);
+  Expr* parse(const char* text, const Path& path, const Path& basePath,
+              StaticEnv& staticEnv);
 
-    string copyPathToStore(PathSet & context, const Path & path);
+ public:
+  /* Do a deep equality test between two values.  That is, list
+     elements and attributes are compared recursively. */
+  bool eqValues(Value& v1, Value& v2);
 
-    /* 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. */
-    Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
+  bool isFunctor(Value& fun);
 
-public:
+  void callFunction(Value& fun, Value& arg, Value& v, const Pos& pos);
+  void callPrimOp(Value& fun, Value& arg, Value& v, const Pos& pos);
 
-    /* The base environment, containing the builtin functions and
-       values. */
-    Env & baseEnv;
+  /* Automatically call a function for which each argument has a
+     default value or has a binding in the `args' map. */
+  void autoCallFunction(Bindings& args, Value& fun, Value& res);
 
-    /* The same, but used during parsing to resolve variables. */
-    StaticEnv staticBaseEnv; // !!! should be private
+  /* Allocation primitives. */
+  Value* allocValue();
+  Env& allocEnv(size_t size);
 
-private:
+  Value* allocAttr(Value& vAttrs, const Symbol& name);
 
-    unsigned int baseEnvDispl = 0;
+  Bindings* allocBindings(size_t capacity);
 
-    void createBaseEnv();
+  void mkList(Value& v, size_t length);
+  void mkAttrs(Value& v, size_t capacity);
+  void mkThunk_(Value& v, Expr* expr);
+  void mkPos(Value& v, Pos* pos);
 
-    Value * addConstant(const string & name, Value & v);
+  void concatLists(Value& v, size_t nrLists, Value** lists, const Pos& pos);
 
-    Value * addPrimOp(const string & name,
-        size_t arity, PrimOpFun primOp);
+  /* Print statistics. */
+  void printStats();
 
-public:
+  void realiseContext(const PathSet& context);
 
-    Value & getBuiltin(const string & name);
+ private:
+  unsigned long nrEnvs = 0;
+  unsigned long nrValuesInEnvs = 0;
+  unsigned long nrValues = 0;
+  unsigned long nrListElems = 0;
+  unsigned long nrAttrsets = 0;
+  unsigned long nrAttrsInAttrsets = 0;
+  unsigned long nrOpUpdates = 0;
+  unsigned long nrOpUpdateValuesCopied = 0;
+  unsigned long nrListConcats = 0;
+  unsigned long nrPrimOpCalls = 0;
+  unsigned long nrFunctionCalls = 0;
 
-private:
+  bool countCalls;
 
-    inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
+  typedef std::map<Symbol, size_t> PrimOpCalls;
+  PrimOpCalls primOpCalls;
 
-    friend struct ExprVar;
-    friend struct ExprAttrs;
-    friend struct ExprLet;
+  typedef std::map<ExprLambda*, size_t> FunctionCalls;
+  FunctionCalls functionCalls;
 
-    Expr * parse(const char * text, const Path & path,
-        const Path & basePath, StaticEnv & staticEnv);
+  void incrFunctionCall(ExprLambda* fun);
 
-public:
+  typedef std::map<Pos, size_t> AttrSelects;
+  AttrSelects attrSelects;
 
-    /* Do a deep equality test between two values.  That is, list
-       elements and attributes are compared recursively. */
-    bool eqValues(Value & v1, Value & v2);
-
-    bool isFunctor(Value & fun);
-
-    void callFunction(Value & fun, Value & arg, Value & v, const Pos & pos);
-    void callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos);
-
-    /* Automatically call a function for which each argument has a
-       default value or has a binding in the `args' map. */
-    void autoCallFunction(Bindings & args, Value & fun, Value & res);
-
-    /* Allocation primitives. */
-    Value * allocValue();
-    Env & allocEnv(size_t size);
-
-    Value * allocAttr(Value & vAttrs, const Symbol & name);
-
-    Bindings * allocBindings(size_t capacity);
-
-    void mkList(Value & v, size_t length);
-    void mkAttrs(Value & v, size_t capacity);
-    void mkThunk_(Value & v, Expr * expr);
-    void mkPos(Value & v, Pos * pos);
-
-    void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos);
-
-    /* Print statistics. */
-    void printStats();
-
-    void realiseContext(const PathSet & context);
-
-private:
-
-    unsigned long nrEnvs = 0;
-    unsigned long nrValuesInEnvs = 0;
-    unsigned long nrValues = 0;
-    unsigned long nrListElems = 0;
-    unsigned long nrAttrsets = 0;
-    unsigned long nrAttrsInAttrsets = 0;
-    unsigned long nrOpUpdates = 0;
-    unsigned long nrOpUpdateValuesCopied = 0;
-    unsigned long nrListConcats = 0;
-    unsigned long nrPrimOpCalls = 0;
-    unsigned long nrFunctionCalls = 0;
-
-    bool countCalls;
-
-    typedef std::map<Symbol, size_t> PrimOpCalls;
-    PrimOpCalls primOpCalls;
-
-    typedef std::map<ExprLambda *, size_t> FunctionCalls;
-    FunctionCalls functionCalls;
-
-    void incrFunctionCall(ExprLambda * fun);
-
-    typedef std::map<Pos, size_t> AttrSelects;
-    AttrSelects attrSelects;
-
-    friend struct ExprOpUpdate;
-    friend struct ExprOpConcatLists;
-    friend struct ExprSelect;
-    friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v);
+  friend struct ExprOpUpdate;
+  friend struct ExprOpConcatLists;
+  friend struct ExprSelect;
+  friend void prim_getAttr(EvalState& state, const Pos& pos, Value** args,
+                           Value& v);
 };
 
-
 /* Return a string representing the type of the value `v'. */
-string showType(const Value & v);
+string showType(const Value& v);
 
 /* Decode a context string ‘!<name>!<path>’ into a pair <path,
    name>. */
-std::pair<string, string> decodeContext(const string & s);
+std::pair<string, string> decodeContext(const string& s);
 
 /* If `path' refers to a directory, then append "/default.nix". */
 Path resolveExprPath(Path path);
 
-struct InvalidPathError : EvalError
-{
-    Path path;
-    InvalidPathError(const Path & path);
+struct InvalidPathError : EvalError {
+  Path path;
+  InvalidPathError(const Path& path);
 #ifdef EXCEPTION_NEEDS_THROW_SPEC
-    ~InvalidPathError() throw () { };
+  ~InvalidPathError() throw(){};
 #endif
 };
 
-struct EvalSettings : Config
-{
-    Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation",
-        "Whether builtin functions that allow executing native code should be enabled."};
-
-    Setting<bool> restrictEval{this, false, "restrict-eval",
-        "Whether to restrict file system access to paths in $NIX_PATH, "
-        "and network access to the URI prefixes listed in 'allowed-uris'."};
-
-    Setting<bool> pureEval{this, false, "pure-eval",
-        "Whether to restrict file system and network access to files specified by cryptographic hash."};
-
-    Setting<bool> enableImportFromDerivation{this, true, "allow-import-from-derivation",
-        "Whether the evaluator allows importing the result of a derivation."};
-
-    Setting<Strings> allowedUris{this, {}, "allowed-uris",
-        "Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
-
-    Setting<bool> traceFunctionCalls{this, false, "trace-function-calls",
-        "Emit log messages for each function entry and exit at the 'vomit' log level (-vvvv)"};
+struct EvalSettings : Config {
+  Setting<bool> enableNativeCode{this, false,
+                                 "allow-unsafe-native-code-during-evaluation",
+                                 "Whether builtin functions that allow "
+                                 "executing native code should be enabled."};
+
+  Setting<bool> restrictEval{
+      this, false, "restrict-eval",
+      "Whether to restrict file system access to paths in $NIX_PATH, "
+      "and network access to the URI prefixes listed in 'allowed-uris'."};
+
+  Setting<bool> pureEval{this, false, "pure-eval",
+                         "Whether to restrict file system and network access "
+                         "to files specified by cryptographic hash."};
+
+  Setting<bool> enableImportFromDerivation{
+      this, true, "allow-import-from-derivation",
+      "Whether the evaluator allows importing the result of a derivation."};
+
+  Setting<Strings> allowedUris{
+      this,
+      {},
+      "allowed-uris",
+      "Prefixes of URIs that builtin functions such as fetchurl and fetchGit "
+      "are allowed to fetch."};
+
+  Setting<bool> traceFunctionCalls{this, false, "trace-function-calls",
+                                   "Emit log messages for each function entry "
+                                   "and exit at the 'vomit' log level (-vvvv)"};
 };
 
 extern EvalSettings evalSettings;
 
-}
+}  // namespace nix