libexpr: move builtin env to new class
Change-Id: Ib76891372be756917bddcf5eaa24ccf8e1288035
This commit is contained in:
parent
1ed0814859
commit
1e064e08fa
|
@ -148,7 +148,7 @@ static void getAllExprs(EvalState & state,
|
|||
vArg->mkString(path2.path.abs());
|
||||
if (seen.size() == maxAttrs)
|
||||
throw Error("too many Nix expressions in directory '%1%'", path);
|
||||
attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg);
|
||||
attrs.alloc(attrName).mkApp(&state.builtins.get("import"), vArg);
|
||||
}
|
||||
else if (st.type == InputAccessor::tDirectory)
|
||||
/* `path2' is a directory (with no default.nix in it);
|
||||
|
|
|
@ -237,7 +237,7 @@ NixRepl::NixRepl(const SearchPath & searchPath, nix::ref<Store> store, EvalState
|
|||
: AbstractNixRepl(state)
|
||||
, debugTraceIndex(0)
|
||||
, getValues(getValues)
|
||||
, staticEnv(new StaticEnv(nullptr, state.staticBaseEnv.get()))
|
||||
, staticEnv(new StaticEnv(nullptr, state.builtins.staticEnv.get()))
|
||||
, interacter(makeInteracter())
|
||||
{
|
||||
}
|
||||
|
@ -784,7 +784,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||
else if (command == ":doc") {
|
||||
Value v;
|
||||
evalString(arg, v);
|
||||
if (auto doc = state.getDoc(v)) {
|
||||
if (auto doc = state.builtins.getDoc(v)) {
|
||||
std::string markdown;
|
||||
|
||||
if (!doc->args.empty() && doc->name) {
|
||||
|
@ -894,12 +894,12 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
|||
void NixRepl::initEnv()
|
||||
{
|
||||
env = &state.mem.allocEnv(envSize);
|
||||
env->up = &state.baseEnv;
|
||||
env->up = &state.builtins.env;
|
||||
displ = 0;
|
||||
staticEnv->vars.clear();
|
||||
|
||||
varNames.clear();
|
||||
for (auto & i : state.staticBaseEnv->vars)
|
||||
for (auto & i : state.builtins.staticEnv->vars)
|
||||
varNames.emplace(state.symbols[i.first]);
|
||||
}
|
||||
|
||||
|
@ -971,7 +971,7 @@ Value * NixRepl::getReplOverlaysEvalFunction()
|
|||
auto & expr = state.parseExprFromString(
|
||||
code,
|
||||
SourcePath(evalReplInitFilesPath),
|
||||
state.staticBaseEnv
|
||||
state.builtins.staticEnv
|
||||
);
|
||||
|
||||
state.eval(expr, **replOverlaysEvalFunction);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: builtins
|
||||
type: attrs
|
||||
constructorArgs: [buildBindings(128).finish()]
|
||||
constructorArgs: [mem.buildBindings(symbols, 128).finish()]
|
||||
renameInGlobalScope: false
|
||||
---
|
||||
Contains all the [built-in functions](@docroot@/language/builtins.md) and values.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: nixPath
|
||||
type: list
|
||||
implementation: getNixPath(*this, searchPath)
|
||||
implementation: prepareNixPath(searchPath)
|
||||
---
|
||||
The search path used to resolve angle bracket path lookups.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: storeDir
|
||||
type: string
|
||||
constructorArgs: [store->config().storeDir]
|
||||
constructorArgs: [storeDir]
|
||||
---
|
||||
Logical file system location of the [Nix store](@docroot@/glossary.md#gloss-store) currently in use.
|
||||
|
||||
|
|
|
@ -262,30 +262,46 @@ EvalMemory::EvalMemory()
|
|||
assert(libexprInitialised);
|
||||
}
|
||||
|
||||
EvalBuiltins::EvalBuiltins(
|
||||
EvalMemory & mem,
|
||||
SymbolTable & symbols,
|
||||
const SearchPath & searchPath,
|
||||
const Path & storeDir,
|
||||
size_t size
|
||||
)
|
||||
: mem(mem)
|
||||
, symbols(symbols)
|
||||
, env(mem.allocEnv(size))
|
||||
, staticEnv{std::make_shared<StaticEnv>(nullptr, nullptr)}
|
||||
{
|
||||
createBaseEnv(searchPath, storeDir);
|
||||
}
|
||||
|
||||
EvalState::EvalState(
|
||||
const SearchPath & _searchPath,
|
||||
ref<Store> store,
|
||||
std::shared_ptr<Store> buildStore)
|
||||
: s(symbols)
|
||||
, searchPath([&] {
|
||||
SearchPath searchPath;
|
||||
if (!evalSettings.pureEval) {
|
||||
for (auto & i : _searchPath.elements)
|
||||
searchPath.elements.emplace_back(SearchPath::Elem {i});
|
||||
for (auto & i : evalSettings.nixPath.get())
|
||||
searchPath.elements.emplace_back(SearchPath::Elem::parse(i));
|
||||
}
|
||||
return searchPath;
|
||||
}())
|
||||
, builtins(mem, symbols, searchPath, store->config().storeDir)
|
||||
, repair(NoRepair)
|
||||
, store(store)
|
||||
, buildStore(buildStore ? buildStore : store)
|
||||
, regexCache(makeRegexCache())
|
||||
, baseEnv(mem.allocEnv(128))
|
||||
, staticBaseEnv{std::make_shared<StaticEnv>(nullptr, nullptr)}
|
||||
{
|
||||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
||||
|
||||
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
||||
|
||||
/* Initialise the Nix expression search path. */
|
||||
if (!evalSettings.pureEval) {
|
||||
for (auto & i : _searchPath.elements)
|
||||
searchPath.elements.emplace_back(SearchPath::Elem {i});
|
||||
for (auto & i : evalSettings.nixPath.get())
|
||||
searchPath.elements.emplace_back(SearchPath::Elem::parse(i));
|
||||
}
|
||||
|
||||
if (evalSettings.restrictEval || evalSettings.pureEval) {
|
||||
allowedPaths = std::optional(PathSet());
|
||||
|
||||
|
@ -308,8 +324,6 @@ EvalState::EvalState(
|
|||
allowPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
createBaseEnv();
|
||||
}
|
||||
|
||||
|
||||
|
@ -426,7 +440,7 @@ Path EvalState::toRealPath(const Path & path, const NixStringContext & context)
|
|||
}
|
||||
|
||||
|
||||
Value * EvalState::addConstant(const std::string & name, const Value & v, Constant info)
|
||||
Value * EvalBuiltins::addConstant(const std::string & name, const Value & v, Constant info)
|
||||
{
|
||||
Value * v2 = mem.allocValue();
|
||||
*v2 = v;
|
||||
|
@ -435,7 +449,7 @@ Value * EvalState::addConstant(const std::string & name, const Value & v, Consta
|
|||
}
|
||||
|
||||
|
||||
void EvalState::addConstant(const std::string & name, Value * v, Constant info)
|
||||
void EvalBuiltins::addConstant(const std::string & name, Value * v, Constant info)
|
||||
{
|
||||
auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
|
||||
|
||||
|
@ -450,9 +464,9 @@ void EvalState::addConstant(const std::string & name, Value * v, Constant info)
|
|||
assert(info.type == gotType);
|
||||
|
||||
/* Install value the base environment. */
|
||||
staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
|
||||
baseEnv.values[baseEnvDispl++] = v;
|
||||
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
|
||||
staticEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
|
||||
env.values[baseEnvDispl++] = v;
|
||||
env.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,7 +477,7 @@ std::ostream & operator<<(std::ostream & output, PrimOp & primOp)
|
|||
return output;
|
||||
}
|
||||
|
||||
Value * EvalState::addPrimOp(PrimOp && primOp)
|
||||
Value * EvalBuiltins::addPrimOp(PrimOp && primOp)
|
||||
{
|
||||
/* Hack to make constants lazy: turn them into a application of
|
||||
the primop to a dummy value. */
|
||||
|
@ -485,20 +499,20 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
|
|||
|
||||
Value * v = mem.allocValue();
|
||||
v->mkPrimOp(new PrimOp(primOp));
|
||||
staticBaseEnv->vars.emplace_back(envName, baseEnvDispl);
|
||||
baseEnv.values[baseEnvDispl++] = v;
|
||||
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(primOp.name), v));
|
||||
staticEnv->vars.emplace_back(envName, baseEnvDispl);
|
||||
env.values[baseEnvDispl++] = v;
|
||||
env.values[0]->attrs->push_back(Attr(symbols.create(primOp.name), v));
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
Value & EvalState::getBuiltin(const std::string & name)
|
||||
Value & EvalBuiltins::get(const std::string & name)
|
||||
{
|
||||
return *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
|
||||
return *env.values[0]->attrs->find(symbols.create(name))->value;
|
||||
}
|
||||
|
||||
|
||||
std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||
std::optional<EvalBuiltins::Doc> EvalBuiltins::getDoc(Value & v)
|
||||
{
|
||||
if (v.isPrimOp()) {
|
||||
auto v2 = &v;
|
||||
|
@ -764,7 +778,7 @@ static inline void mkThunk(Value & v, Env & env, Expr & expr)
|
|||
|
||||
void EvalState::mkThunk_(Value & v, Expr & expr)
|
||||
{
|
||||
mkThunk(v, baseEnv, expr);
|
||||
mkThunk(v, builtins.env, expr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -927,7 +941,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v)
|
|||
? makeDebugTraceStacker(
|
||||
*this,
|
||||
e,
|
||||
this->baseEnv,
|
||||
this->builtins.env,
|
||||
e.getPos() ? std::make_shared<Pos>(positions[e.getPos()]) : nullptr,
|
||||
"while evaluating the file '%1%':", resolvedPath.to_string())
|
||||
: nullptr;
|
||||
|
@ -951,7 +965,7 @@ void EvalState::resetFileCache()
|
|||
|
||||
void EvalState::eval(Expr & e, Value & v)
|
||||
{
|
||||
e.eval(*this, baseEnv, v);
|
||||
e.eval(*this, builtins.env, v);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2667,7 +2681,7 @@ SourcePath resolveExprPath(SourcePath path)
|
|||
|
||||
Expr & EvalState::parseExprFromFile(const SourcePath & path)
|
||||
{
|
||||
return parseExprFromFile(path, staticBaseEnv);
|
||||
return parseExprFromFile(path, builtins.staticEnv);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2696,7 +2710,7 @@ Expr & EvalState::parseExprFromString(
|
|||
const FeatureSettings & featureSettings
|
||||
)
|
||||
{
|
||||
return parseExprFromString(std::move(s), basePath, staticBaseEnv, featureSettings);
|
||||
return parseExprFromString(std::move(s), basePath, builtins.staticEnv, featureSettings);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2704,7 +2718,9 @@ Expr & EvalState::parseStdin()
|
|||
{
|
||||
//Activity act(*logger, lvlTalkative, "parsing standard input");
|
||||
auto s = make_ref<std::string>(drainFD(0));
|
||||
return *parse(s->data(), s->size(), Pos::Stdin{.source = s}, CanonPath::fromCwd(), staticBaseEnv);
|
||||
return *parse(
|
||||
s->data(), s->size(), Pos::Stdin{.source = s}, CanonPath::fromCwd(), builtins.staticEnv
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -263,15 +263,88 @@ private:
|
|||
Statistics stats;
|
||||
};
|
||||
|
||||
class EvalBuiltins
|
||||
{
|
||||
EvalMemory & mem;
|
||||
SymbolTable & symbols;
|
||||
|
||||
public:
|
||||
explicit EvalBuiltins(
|
||||
EvalMemory & mem,
|
||||
SymbolTable & symbols,
|
||||
const SearchPath & searchPath,
|
||||
const Path & storeDir,
|
||||
size_t size = 128
|
||||
);
|
||||
|
||||
/**
|
||||
* The base environment, containing the builtin functions and
|
||||
* values.
|
||||
*/
|
||||
Env & env;
|
||||
|
||||
/**
|
||||
* The same, but used during parsing to resolve variables.
|
||||
*/
|
||||
std::shared_ptr<StaticEnv> staticEnv; // !!! should be private
|
||||
|
||||
/**
|
||||
* Name and documentation about every constant.
|
||||
*
|
||||
* Constants from primops are hard to crawl, and their docs will go
|
||||
* here too.
|
||||
*/
|
||||
std::vector<std::pair<std::string, Constant>> constantInfos;
|
||||
|
||||
private:
|
||||
unsigned int baseEnvDispl = 0;
|
||||
|
||||
void createBaseEnv(const SearchPath & searchPath, const Path & storeDir);
|
||||
|
||||
Value * addConstant(const std::string & name, const Value & v, Constant info);
|
||||
|
||||
void addConstant(const std::string & name, Value * v, Constant info);
|
||||
|
||||
Value * addPrimOp(PrimOp && primOp);
|
||||
|
||||
Value prepareNixPath(const SearchPath & searchPath);
|
||||
|
||||
public:
|
||||
Value & get(const std::string & name);
|
||||
|
||||
struct Doc
|
||||
{
|
||||
Pos pos;
|
||||
std::optional<std::string> name;
|
||||
size_t arity;
|
||||
std::vector<std::string> args;
|
||||
/**
|
||||
* Unlike the other `doc` fields in this file, this one should never be
|
||||
* `null`.
|
||||
*/
|
||||
const char * doc;
|
||||
};
|
||||
|
||||
std::optional<Doc> getDoc(Value & v);
|
||||
};
|
||||
|
||||
|
||||
class EvalState
|
||||
{
|
||||
friend class EvalBuiltins;
|
||||
|
||||
public:
|
||||
SymbolTable symbols;
|
||||
PosTable positions;
|
||||
const StaticSymbols s;
|
||||
EvalMemory mem;
|
||||
|
||||
private:
|
||||
SearchPath searchPath;
|
||||
|
||||
public:
|
||||
EvalBuiltins builtins;
|
||||
|
||||
/**
|
||||
* If set, force copying files to the Nix store even if they
|
||||
* already exist there.
|
||||
|
@ -318,8 +391,6 @@ private:
|
|||
using FileEvalCache = GcMap<SourcePath, Value>;
|
||||
FileEvalCache fileEvalCache;
|
||||
|
||||
SearchPath searchPath;
|
||||
|
||||
std::map<std::string, std::optional<std::string>> searchPathResolved;
|
||||
|
||||
/**
|
||||
|
@ -529,58 +600,6 @@ public:
|
|||
*/
|
||||
SingleDerivedPath coerceToSingleDerivedPath(const PosIdx pos, Value & v, std::string_view errorCtx);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The base environment, containing the builtin functions and
|
||||
* values.
|
||||
*/
|
||||
Env & baseEnv;
|
||||
|
||||
/**
|
||||
* The same, but used during parsing to resolve variables.
|
||||
*/
|
||||
std::shared_ptr<StaticEnv> staticBaseEnv; // !!! should be private
|
||||
|
||||
/**
|
||||
* Name and documentation about every constant.
|
||||
*
|
||||
* Constants from primops are hard to crawl, and their docs will go
|
||||
* here too.
|
||||
*/
|
||||
std::vector<std::pair<std::string, Constant>> constantInfos;
|
||||
|
||||
private:
|
||||
|
||||
unsigned int baseEnvDispl = 0;
|
||||
|
||||
void createBaseEnv();
|
||||
|
||||
Value * addConstant(const std::string & name, const Value & v, Constant info);
|
||||
|
||||
void addConstant(const std::string & name, Value * v, Constant info);
|
||||
|
||||
Value * addPrimOp(PrimOp && primOp);
|
||||
|
||||
public:
|
||||
|
||||
Value & getBuiltin(const std::string & name);
|
||||
|
||||
struct Doc
|
||||
{
|
||||
Pos pos;
|
||||
std::optional<std::string> name;
|
||||
size_t arity;
|
||||
std::vector<std::string> args;
|
||||
/**
|
||||
* Unlike the other `doc` fields in this file, this one should never be
|
||||
* `null`.
|
||||
*/
|
||||
const char * doc;
|
||||
};
|
||||
|
||||
std::optional<Doc> getDoc(Value & v);
|
||||
|
||||
private:
|
||||
|
||||
inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
|
||||
|
|
|
@ -231,9 +231,11 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
|||
state.forceAttrs(*vScope, pos, "while evaluating the first argument passed to builtins.scopedImport");
|
||||
|
||||
Env * env = &state.mem.allocEnv(vScope->attrs->size());
|
||||
env->up = &state.baseEnv;
|
||||
env->up = &state.builtins.env;
|
||||
|
||||
auto staticEnv = std::make_shared<StaticEnv>(nullptr, state.staticBaseEnv.get(), vScope->attrs->size());
|
||||
auto staticEnv = std::make_shared<StaticEnv>(
|
||||
nullptr, state.builtins.staticEnv.get(), vScope->attrs->size()
|
||||
);
|
||||
|
||||
unsigned int displ = 0;
|
||||
for (auto & attr : *vScope->attrs) {
|
||||
|
@ -1375,7 +1377,7 @@ static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Va
|
|||
auto epath = state.mem.allocValue();
|
||||
epath->mkPath(path + name);
|
||||
if (!readFileType)
|
||||
readFileType = &state.getBuiltin("readFileType");
|
||||
readFileType = &state.builtins.get("readFileType");
|
||||
attr.mkApp(readFileType, epath);
|
||||
} else {
|
||||
// This branch of the conditional is much more likely.
|
||||
|
@ -2785,23 +2787,23 @@ RegisterPrimOp::RegisterPrimOp(PrimOp && primOp)
|
|||
}
|
||||
|
||||
|
||||
static Value getNixPath(EvalState & state, SearchPath & searchPath)
|
||||
Value EvalBuiltins::prepareNixPath(const SearchPath & searchPath)
|
||||
{
|
||||
Value v;
|
||||
v = state.mem.newList(searchPath.elements.size());
|
||||
v = mem.newList(searchPath.elements.size());
|
||||
int n = 0;
|
||||
for (auto & i : searchPath.elements) {
|
||||
auto attrs = state.buildBindings(2);
|
||||
auto attrs = mem.buildBindings(symbols, 2);
|
||||
attrs.alloc("path").mkString(i.path.s);
|
||||
attrs.alloc("prefix").mkString(i.prefix.s);
|
||||
(v.listElems()[n++] = state.mem.allocValue())->mkAttrs(attrs);
|
||||
(v.listElems()[n++] = mem.allocValue())->mkAttrs(attrs);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void EvalState::createBaseEnv()
|
||||
void EvalBuiltins::createBaseEnv(const SearchPath & searchPath, const Path & storeDir)
|
||||
{
|
||||
baseEnv.up = 0;
|
||||
env.up = 0;
|
||||
|
||||
// constants include the magic `builtins` which must come first
|
||||
#include "register-builtin-constants.gen.inc"
|
||||
|
@ -2838,7 +2840,7 @@ void EvalState::createBaseEnv()
|
|||
#include "primops/derivation.nix.gen.hh"
|
||||
;
|
||||
auto & expr = *state.parse(
|
||||
code, sizeof(code), Pos::Hidden{}, {CanonPath::root}, state.staticBaseEnv
|
||||
code, sizeof(code), Pos::Hidden{}, {CanonPath::root}, state.builtins.staticEnv
|
||||
);
|
||||
state.eval(expr, v);
|
||||
},
|
||||
|
@ -2857,11 +2859,10 @@ void EvalState::createBaseEnv()
|
|||
|
||||
/* Now that we've added all primops, sort the `builtins' set,
|
||||
because attribute lookups expect it to be sorted. */
|
||||
baseEnv.values[0]->attrs->sort();
|
||||
|
||||
staticBaseEnv->sort();
|
||||
staticBaseEnv->isRoot = true;
|
||||
env.values[0]->attrs->sort();
|
||||
|
||||
staticEnv->sort();
|
||||
staticEnv->isRoot = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ static void showHelp(std::vector<std::string> subcommand, NixArgs & toplevel)
|
|||
vDump->mkString(toplevel.dumpCli());
|
||||
|
||||
auto vRes = state.mem.allocValue();
|
||||
state.callFunction(*vGenerateManpage, state.getBuiltin("false"), *vRes, noPos);
|
||||
state.callFunction(*vGenerateManpage, state.builtins.get("false"), *vRes, noPos);
|
||||
state.callFunction(*vRes, *vDump, *vRes, noPos);
|
||||
|
||||
auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
|
||||
|
@ -414,7 +414,7 @@ void mainWrapped(int argc, char * * argv)
|
|||
auto res = nlohmann::json::object();
|
||||
res["builtins"] = ({
|
||||
auto builtinsJson = nlohmann::json::object();
|
||||
auto builtins = state.baseEnv.values[0]->attrs;
|
||||
auto builtins = state.builtins.env.values[0]->attrs;
|
||||
for (auto & builtin : *builtins) {
|
||||
auto b = nlohmann::json::object();
|
||||
if (!builtin.value->isPrimOp()) continue;
|
||||
|
@ -430,7 +430,7 @@ void mainWrapped(int argc, char * * argv)
|
|||
});
|
||||
res["constants"] = ({
|
||||
auto constantsJson = nlohmann::json::object();
|
||||
for (auto & [name, info] : state.constantInfos) {
|
||||
for (auto & [name, info] : state.builtins.constantInfos) {
|
||||
auto c = nlohmann::json::object();
|
||||
if (!info.doc) continue;
|
||||
c["doc"] = trim(stripIndentation(info.doc));
|
||||
|
|
Loading…
Reference in a new issue