Merge pull request #9370 from hercules-ci/add-value-types

refactor: Add `Value` types, use `std::span` for list iteration
This commit is contained in:
tomberek 2023-11-20 01:32:32 -05:00 committed by GitHub
commit fb68699456
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 74 deletions

View File

@ -3,6 +3,7 @@
#include <cassert> #include <cassert>
#include <climits> #include <climits>
#include <span>
#include "symbol-table.hh" #include "symbol-table.hh"
#include "value/context.hh" #include "value/context.hh"
@ -158,42 +159,60 @@ public:
inline bool isPrimOp() const { return internalType == tPrimOp; }; inline bool isPrimOp() const { return internalType == tPrimOp; };
inline bool isPrimOpApp() const { return internalType == tPrimOpApp; }; inline bool isPrimOpApp() const { return internalType == tPrimOpApp; };
/**
* 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 StringWithContext {
const char * c_str;
const char * * context; // must be in sorted order
};
struct Path {
InputAccessor * accessor;
const char * path;
};
struct ClosureThunk {
Env * env;
Expr * expr;
};
struct FunctionApplicationThunk {
Value * left, * right;
};
struct Lambda {
Env * env;
ExprLambda * fun;
};
union union
{ {
NixInt integer; NixInt integer;
bool boolean; bool boolean;
/** StringWithContext string;
* 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" Path _path;
* 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 {
const char * c_str;
const char * * context; // must be in sorted order
} string;
struct {
InputAccessor * accessor;
const char * path;
} _path;
Bindings * attrs; Bindings * attrs;
struct { struct {
@ -201,21 +220,11 @@ public:
Value * * elems; Value * * elems;
} bigList; } bigList;
Value * smallList[2]; Value * smallList[2];
struct { ClosureThunk thunk;
Env * env; FunctionApplicationThunk app;
Expr * expr; Lambda lambda;
} thunk;
struct {
Value * left, * right;
} app;
struct {
Env * env;
ExprLambda * fun;
} lambda;
PrimOp * primOp; PrimOp * primOp;
struct { FunctionApplicationThunk primOpApp;
Value * left, * right;
} primOpApp;
ExternalValueBase * external; ExternalValueBase * external;
NixFloat fpoint; NixFloat fpoint;
}; };
@ -387,7 +396,13 @@ public:
return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems; return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
} }
const Value * const * listElems() const std::span<Value * const> listItems() const
{
assert(isList());
return std::span<Value * const>(listElems(), listSize());
}
Value * const * listElems() const
{ {
return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems; return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
} }
@ -406,34 +421,6 @@ public:
*/ */
bool isTrivial() const; bool isTrivial() const;
auto listItems()
{
struct ListIterable
{
typedef Value * const * iterator;
iterator _begin, _end;
iterator begin() const { return _begin; }
iterator end() const { return _end; }
};
assert(isList());
auto begin = listElems();
return ListIterable { begin, begin + listSize() };
}
auto listItems() const
{
struct ConstListIterable
{
typedef const Value * const * iterator;
iterator _begin, _end;
iterator begin() const { return _begin; }
iterator end() const { return _end; }
};
assert(isList());
auto begin = listElems();
return ConstListIterable { begin, begin + listSize() };
}
SourcePath path() const SourcePath path() const
{ {
assert(internalType == tPath); assert(internalType == tPath);

View File

@ -172,7 +172,7 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v
directory). */ directory). */
else if (st.type == InputAccessor::tDirectory) { else if (st.type == InputAccessor::tDirectory) {
auto attrs = state.buildBindings(maxAttrs); auto attrs = state.buildBindings(maxAttrs);
attrs.alloc("_combineChannels").mkList(0); state.mkList(attrs.alloc("_combineChannels"), 0);
StringSet seen; StringSet seen;
getAllExprs(state, path, seen, attrs); getAllExprs(state, path, seen, attrs);
v.mkAttrs(attrs); v.mkAttrs(attrs);