diff options
Diffstat (limited to 'third_party/nix/src/libexpr/value.hh')
-rw-r--r-- | third_party/nix/src/libexpr/value.hh | 257 |
1 files changed, 257 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..892c11220e42 --- /dev/null +++ b/third_party/nix/src/libexpr/value.hh @@ -0,0 +1,257 @@ +#pragma once + +#include "symbol-table.hh" +#include "types.hh" + +#if HAVE_BOEHMGC +#include <gc/gc_allocator.h> +#endif + +namespace nix { + +typedef enum { + tInt = 1, + tBool, + tString, + tPath, + tNull, + tAttrs, + tList1, + tList2, + tListN, + tThunk, + tApp, + tLambda, + tBlackhole, + tPrimOp, + tPrimOpApp, + tExternal, + tFloat +} ValueType; + +class Bindings; +struct Env; +struct Expr; +struct ExprLambda; +struct PrimOp; +struct PrimOp; +class Symbol; +struct Pos; +class EvalState; +class XMLWriter; +class JSONPlaceholder; + +typedef int64_t NixInt; +typedef double NixFloat; + +/* External values must descend from ExternalValueBase, so that + * type-agnostic nix functions (e.g. showType) can be implemented + */ +class ExternalValueBase { + friend std::ostream& operator<<(std::ostream& str, + const ExternalValueBase& v); + + protected: + /* Print out the value */ + virtual std::ostream& print(std::ostream& str) const = 0; + + public: + /* Return a simple string describing the type */ + virtual std::string showType() const = 0; + + /* Return a string to be used in builtins.typeOf */ + virtual std::string typeOf() const = 0; + + /* How much space does this value take up */ + virtual size_t valueSize(std::set<const void*>& seen) const = 0; + + /* Coerce the value to a string. Defaults to uncoercable, i.e. throws an + * error + */ + virtual std::string coerceToString(const Pos& pos, PathSet& context, + bool copyMore, bool copyToStore) const; + + /* Compare to another value of the same type. Defaults to uncomparable, + * i.e. always false. + */ + virtual bool operator==(const ExternalValueBase& b) const; + + /* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */ + virtual void printValueAsJSON(EvalState& state, bool strict, + JSONPlaceholder& out, PathSet& context) const; + + /* Print the value as XML. Defaults to unevaluated */ + virtual void printValueAsXML(EvalState& state, bool strict, bool location, + XMLWriter& doc, PathSet& context, + PathSet& drvsSeen) const; + + virtual ~ExternalValueBase(){}; +}; + +std::ostream& operator<<(std::ostream& str, const ExternalValueBase& v); + +// 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 NixBigList { + size_t size; + Value** elems; +}; + +struct NixThunk { + Env* env; + Expr* expr; +}; + +struct NixApp { + Value *left, *right; +}; + +struct NixLambda { + Env* env; + ExprLambda* fun; +}; + +struct NixPrimOpApp { + Value *left, *right; +}; + +struct Value { + ValueType type; + union { // TODO(tazjin): std::variant + NixInt integer; + bool boolean; + NixString string; + const char* path; + Bindings* attrs; + NixBigList bigList; + Value* smallList[2]; + NixThunk thunk; + NixApp app; // TODO(tazjin): "app"? + NixLambda lambda; + PrimOp* primOp; + NixPrimOpApp primOpApp; + ExternalValueBase* external; + NixFloat fpoint; + }; + + bool isList() const { + return type == tList1 || type == tList2 || type == tListN; + } + + Value** listElems() { + return type == tList1 || type == tList2 ? smallList : bigList.elems; + } + + const Value* const* listElems() const { + return type == tList1 || type == tList2 ? smallList : bigList.elems; + } + + size_t listSize() const { + return type == tList1 ? 1 : type == tList2 ? 2 : bigList.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(Value& v); + +#if HAVE_BOEHMGC +typedef std::vector<Value*, gc_allocator<Value*> > ValueVector; +typedef std::map<Symbol, Value*, std::less<Symbol>, + gc_allocator<std::pair<const Symbol, Value*> > > + ValueMap; +#else +typedef std::vector<Value*> ValueVector; +typedef std::map<Symbol, Value*> ValueMap; +#endif + +} // namespace nix |