diff options
Diffstat (limited to 'third_party/nix/src/libexpr/value.hh')
-rw-r--r-- | third_party/nix/src/libexpr/value.hh | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/third_party/nix/src/libexpr/value.hh b/third_party/nix/src/libexpr/value.hh new file mode 100644 index 000000000000..82021c77c41b --- /dev/null +++ b/third_party/nix/src/libexpr/value.hh @@ -0,0 +1,191 @@ +#pragma once + +#include <tuple> +#include <vector> + +#include "libexpr/symbol-table.hh" +#include "libutil/types.hh" + +namespace nix { + +using ValueType = enum { + tInt = 1, + tBool, + tString, + tPath, + tNull, + tAttrs, + tList, + tThunk, + tApp, + tLambda, + tBlackhole, + tPrimOp, + tPrimOpApp, + _reserved1, // formerly tExternal + tFloat +}; + +class Bindings; +struct Env; +struct Expr; +struct ExprLambda; +struct PrimOp; +struct PrimOp; +class Symbol; + +typedef int64_t NixInt; +typedef double NixFloat; + +// Forward declaration of Value is required because the following +// types are mutually recursive. +// +// TODO(tazjin): Really, these types need some serious refactoring. +struct Value; + +/* Strings in the evaluator carry a so-called `context' which + is a list of strings representing store paths. This is to + allow users to write things like + + "--with-freetype2-library=" + freetype + "/lib" + + where `freetype' is a derivation (or a source to be copied + to the store). If we just concatenated the strings without + keeping track of the referenced store paths, then if the + string is used as a derivation attribute, the derivation + will not have the correct dependencies in its inputDrvs and + inputSrcs. + + The semantics of the context is as follows: when a string + with context C is used as a derivation attribute, then the + derivations in C will be added to the inputDrvs of the + derivation, and the other store paths in C will be added to + the inputSrcs of the derivations. + + For canonicity, the store paths should be in sorted order. */ +struct NixString { + const char* s; + const char** context; // must be in sorted order +}; + +struct NixThunk { + Env* env; + Expr* expr; +}; + +struct NixApp { + Value *left, *right; +}; + +struct NixLambda { + Env* env; + ExprLambda* fun; +}; + +struct NixPrimOpApp { + Value *left, *right; +}; + +using NixList = std::vector<Value*>; + +struct Value { + ValueType type; + union { // TODO(tazjin): std::variant + NixInt integer; + bool boolean; + NixString string; + const char* path; + std::shared_ptr<Bindings> attrs; + std::shared_ptr<NixList> list; + NixThunk thunk; + NixApp app; // TODO(tazjin): "app"? + NixLambda lambda; + std::shared_ptr<PrimOp> primOp; + NixPrimOpApp primOpApp; + NixFloat fpoint; + }; + + Value() : type(tInt), attrs(nullptr) { + static_assert(offsetof(Value, attrs) + sizeof(attrs) == sizeof(Value)); + } + + Value(const Value& copy); + Value(Value&& move); + ~Value() {} + Value& operator=(const Value& copy); + Value& operator=(Value&& move); + + bool isList() const { return type == tList; } + + size_t listSize() const { return list->size(); } +}; + +/* After overwriting an app node, be sure to clear pointers in the + Value to ensure that the target isn't kept alive unnecessarily. */ +static inline void clearValue(Value& v) { v.app.left = v.app.right = 0; } + +static inline void mkInt(Value& v, NixInt n) { + clearValue(v); + v.type = tInt; + v.integer = n; +} + +static inline void mkFloat(Value& v, NixFloat n) { + clearValue(v); + v.type = tFloat; + v.fpoint = n; +} + +static inline void mkBool(Value& v, bool b) { + clearValue(v); + v.type = tBool; + v.boolean = b; +} + +static inline void mkNull(Value& v) { + clearValue(v); + v.type = tNull; +} + +static inline void mkApp(Value& v, Value& left, Value& right) { + v.type = tApp; + v.app.left = &left; + v.app.right = &right; +} + +static inline void mkPrimOpApp(Value& v, Value& left, Value& right) { + v.type = tPrimOpApp; + v.app.left = &left; + v.app.right = &right; +} + +static inline void mkStringNoCopy(Value& v, const char* s) { + v.type = tString; + v.string.s = s; + v.string.context = 0; +} + +static inline void mkString(Value& v, const Symbol& s) { + mkStringNoCopy(v, ((const std::string&)s).c_str()); +} + +void mkString(Value& v, const char* s); + +static inline void mkPathNoCopy(Value& v, const char* s) { + clearValue(v); + v.type = tPath; + v.path = s; +} + +void mkPath(Value& v, const char* s); + +/* Compute the size in bytes of the given value, including all values + and environments reachable from it. Static expressions (Exprs) are + not included. */ +size_t valueSize(const Value& v); + +using ValueMap = std::map<Symbol, Value*>; + +std::shared_ptr<Value*> allocRootValue(Value* v); + +} // namespace nix |