aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/value.hh
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2021-09-15 20:33:44 +0200
committerGitHub <noreply@github.com>2021-09-15 20:33:44 +0200
commit79152e307e7eef667c3de9c21571d017654a7c32 (patch)
tree67fd413bcf0b42c5ada7eddc41a04f7bd99df3a8 /src/libexpr/value.hh
parent7349f257da8278af9aae35544b15c9a204e2a57b (diff)
parent3b82c1a5fef521ebadea5df12384390c8c24100c (diff)
Merge pull request #5212 from mkenigs/auto-uid-allocation
Merge master into #3600
Diffstat (limited to 'src/libexpr/value.hh')
-rw-r--r--src/libexpr/value.hh253
1 files changed, 196 insertions, 57 deletions
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 71025824e..a1f131f9e 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -27,8 +27,24 @@ typedef enum {
tPrimOpApp,
tExternal,
tFloat
-} ValueType;
+} InternalType;
+// This type abstracts over all actual value types in the language,
+// grouping together implementation details like tList*, different function
+// types, and types in non-normal form (so thunks and co.)
+typedef enum {
+ nThunk,
+ nInt,
+ nFloat,
+ nBool,
+ nString,
+ nPath,
+ nNull,
+ nAttrs,
+ nList,
+ nFunction,
+ nExternal
+} ValueType;
class Bindings;
struct Env;
@@ -90,7 +106,28 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
struct Value
{
- ValueType type;
+private:
+ InternalType internalType;
+
+friend std::string showType(const Value & v);
+friend void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v);
+
+public:
+
+ // Functions needed to distinguish the type
+ // These should be removed eventually, by putting the functionality that's
+ // needed by callers into methods of this type
+
+ // type() == nThunk
+ inline bool isThunk() const { return internalType == tThunk; };
+ inline bool isApp() const { return internalType == tApp; };
+ inline bool isBlackhole() const { return internalType == tBlackhole; };
+
+ // type() == nFunction
+ inline bool isLambda() const { return internalType == tLambda; };
+ inline bool isPrimOp() const { return internalType == tPrimOp; };
+ inline bool isPrimOpApp() const { return internalType == tPrimOpApp; };
+
union
{
NixInt integer;
@@ -147,108 +184,210 @@ struct Value
NixFloat fpoint;
};
+ // Returns the normal type of a Value. This only returns nThunk if the
+ // Value hasn't been forceValue'd
+ inline ValueType type() const
+ {
+ switch (internalType) {
+ case tInt: return nInt;
+ case tBool: return nBool;
+ case tString: return nString;
+ case tPath: return nPath;
+ case tNull: return nNull;
+ case tAttrs: return nAttrs;
+ case tList1: case tList2: case tListN: return nList;
+ case tLambda: case tPrimOp: case tPrimOpApp: return nFunction;
+ case tExternal: return nExternal;
+ case tFloat: return nFloat;
+ case tThunk: case tApp: case tBlackhole: return nThunk;
+ }
+ abort();
+ }
+
+ /* After overwriting an app node, be sure to clear pointers in the
+ Value to ensure that the target isn't kept alive unnecessarily. */
+ inline void clearValue()
+ {
+ app.left = app.right = 0;
+ }
+
+ inline void mkInt(NixInt n)
+ {
+ clearValue();
+ internalType = tInt;
+ integer = n;
+ }
+
+ inline void mkBool(bool b)
+ {
+ clearValue();
+ internalType = tBool;
+ boolean = b;
+ }
+
+ inline void mkString(const char * s, const char * * context = 0)
+ {
+ internalType = tString;
+ string.s = s;
+ string.context = context;
+ }
+
+ inline void mkPath(const char * s)
+ {
+ clearValue();
+ internalType = tPath;
+ path = s;
+ }
+
+ inline void mkNull()
+ {
+ clearValue();
+ internalType = tNull;
+ }
+
+ inline void mkAttrs(Bindings * a)
+ {
+ clearValue();
+ internalType = tAttrs;
+ attrs = a;
+ }
+
+ inline void mkList(size_t size)
+ {
+ clearValue();
+ if (size == 1)
+ internalType = tList1;
+ else if (size == 2)
+ internalType = tList2;
+ else {
+ internalType = tListN;
+ bigList.size = size;
+ }
+ }
+
+ inline void mkThunk(Env * e, Expr * ex)
+ {
+ internalType = tThunk;
+ thunk.env = e;
+ thunk.expr = ex;
+ }
+
+ inline void mkApp(Value * l, Value * r)
+ {
+ internalType = tApp;
+ app.left = l;
+ app.right = r;
+ }
+
+ inline void mkLambda(Env * e, ExprLambda * f)
+ {
+ internalType = tLambda;
+ lambda.env = e;
+ lambda.fun = f;
+ }
+
+ inline void mkBlackhole()
+ {
+ internalType = tBlackhole;
+ // Value will be overridden anyways
+ }
+
+ inline void mkPrimOp(PrimOp * p)
+ {
+ clearValue();
+ internalType = tPrimOp;
+ primOp = p;
+ }
+
+
+ inline void mkPrimOpApp(Value * l, Value * r)
+ {
+ internalType = tPrimOpApp;
+ app.left = l;
+ app.right = r;
+ }
+
+ inline void mkExternal(ExternalValueBase * e)
+ {
+ clearValue();
+ internalType = tExternal;
+ external = e;
+ }
+
+ inline void mkFloat(NixFloat n)
+ {
+ clearValue();
+ internalType = tFloat;
+ fpoint = n;
+ }
+
bool isList() const
{
- return type == tList1 || type == tList2 || type == tListN;
+ return internalType == tList1 || internalType == tList2 || internalType == tListN;
}
Value * * listElems()
{
- return type == tList1 || type == tList2 ? smallList : bigList.elems;
+ return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
}
const Value * const * listElems() const
{
- return type == tList1 || type == tList2 ? smallList : bigList.elems;
+ return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
}
size_t listSize() const
{
- return type == tList1 ? 1 : type == tList2 ? 2 : bigList.size;
+ return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size;
}
-};
+ Pos determinePos(const Pos &pos) const;
-/* 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;
-}
+ /* Check whether forcing this value requires a trivial amount of
+ computation. In particular, function applications are
+ non-trivial. */
+ bool isTrivial() const;
+
+ std::vector<std::pair<Path, std::string>> getContext();
+};
+
+// TODO: Remove these static functions, replace call sites with v.mk* instead
static inline void mkInt(Value & v, NixInt n)
{
- clearValue(v);
- v.type = tInt;
- v.integer = n;
+ v.mkInt(n);
}
-
static inline void mkFloat(Value & v, NixFloat n)
{
- clearValue(v);
- v.type = tFloat;
- v.fpoint = n;
+ v.mkFloat(n);
}
-
static inline void mkBool(Value & v, bool b)
{
- clearValue(v);
- v.type = tBool;
- v.boolean = b;
+ v.mkBool(b);
}
-
static inline void mkNull(Value & v)
{
- clearValue(v);
- v.type = tNull;
+ v.mkNull();
}
-
static inline void mkApp(Value & v, Value & left, Value & right)
{
- v.type = tApp;
- v.app.left = &left;
- v.app.right = &right;
+ v.mkApp(&left, &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 string &) s).c_str());
+ v.mkString(((const 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);