primops.cc: cleanup

Change-Id: Iae0580e8f44988b8452aef77e67ca2495c342bf6
This commit is contained in:
Tom Hubrecht 2024-05-30 10:29:15 +02:00
parent 8035abdc37
commit 09139554a8

View file

@ -1,20 +1,10 @@
#include "archive.hh"
#include "derivations.hh" #include "derivations.hh"
#include "downstream-placeholder.hh"
#include "eval-inline.hh"
#include "eval.hh" #include "eval.hh"
#include "eval-settings.hh" #include "eval-settings.hh"
#include "gc-small-vector.hh" #include "gc-small-vector.hh"
#include "globals.hh"
#include "json-to-value.hh" #include "json-to-value.hh"
#include "names.hh"
#include "path-references.hh"
#include "store-api.hh" #include "store-api.hh"
#include "util.hh"
#include "value-to-json.hh"
#include "value-to-xml.hh"
#include "primops.hh" #include "primops.hh"
#include "fetch-to-store.hh"
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -24,147 +14,20 @@
#include <unistd.h> #include <unistd.h>
#include <algorithm> #include <algorithm>
#include <cstring>
#include <regex>
#include <dlfcn.h> #include <dlfcn.h>
#include <cmath>
namespace nix { namespace nix {
/*************************************************************
* Miscellaneous
*************************************************************/
/* Execute a program and parse its output */
template<typename Callable>
static inline void withExceptionContext(Trace trace, Callable&& func)
{
try
{
func();
}
catch(Error & e)
{
e.pushTrace(trace);
throw;
}
}
/* Try evaluating the argument. Success => {success=true; value=something;},
* else => {success=false; value=false;} */
/* Return an environment variable. Use with care. */
/* Evaluate the first argument, then return the second argument. */
/*************************************************************
* Derivations
*************************************************************/
static void derivationStrictInternal(EvalState & state, const std::string & name, Bindings * attrs, Value & v);
/*************************************************************
* Paths
*************************************************************/
/*************************************************************
* Creating files
*************************************************************/
/* Convert the argument (which can be any Nix expression) to an XML
representation returned in a string. Not all Nix expressions can
be sensibly or completely represented (e.g., functions). */
/* Store a string in the Nix store as a source file that can be used
as an input by derivations. */
/*************************************************************
* Sets
*************************************************************/
/* Determine whether the argument is a set. */
/* Builds a set from a list specifying (name, value) pairs. To be
precise, a list [{name = "name1"; value = value1;} ... {name =
"nameN"; value = valueN;}] is transformed to {name1 = value1;
... nameN = valueN;}. In case of duplicate occurrences of the same
name, the first takes precedence. */
/* */
/*************************************************************
* Lists
*************************************************************/
/* Return the first element of a list. */
/* Apply a function to every element of a list. */
/* Return the length of a list. This is an O(1) time operation. */
/*************************************************************
* Integer arithmetic
*************************************************************/
/*************************************************************
* String manipulation
*************************************************************/
/*************************************************************
* Versions
*************************************************************/
/*************************************************************
* Primop registration
*************************************************************/
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps; RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
RegisterPrimOp::RegisterPrimOp(PrimOp && primOp) RegisterPrimOp::RegisterPrimOp(PrimOp && primOp)
{ {
if (!primOps) primOps = new PrimOps; if (!primOps) {
primOps = new PrimOps;
}
primOps->push_back(std::move(primOp)); primOps->push_back(std::move(primOp));
} }
void EvalState::createBaseEnv() void EvalState::createBaseEnv()
{ {
baseEnv.up = 0; baseEnv.up = 0;
@ -174,9 +37,12 @@ void EvalState::createBaseEnv()
/* `builtins' must be first! */ /* `builtins' must be first! */
v.mkAttrs(buildBindings(128).finish()); v.mkAttrs(buildBindings(128).finish());
addConstant("builtins", v, { addConstant(
.type = nAttrs, "builtins",
.doc = R"( v,
{
.type = nAttrs,
.doc = R"(
Contains all the [built-in functions](@docroot@/language/builtins.md) and values. Contains all the [built-in functions](@docroot@/language/builtins.md) and values.
Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations: Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations:
@ -186,12 +52,16 @@ void EvalState::createBaseEnv()
if builtins ? hasContext then builtins.hasContext s else true if builtins ? hasContext then builtins.hasContext s else true
``` ```
)", )",
}); }
);
v.mkBool(true); v.mkBool(true);
addConstant("true", v, { addConstant(
.type = nBool, "true",
.doc = R"( v,
{
.type = nBool,
.doc = R"(
Primitive value. Primitive value.
It can be returned by It can be returned by
@ -206,12 +76,16 @@ void EvalState::createBaseEnv()
1 1
``` ```
)", )",
}); }
);
v.mkBool(false); v.mkBool(false);
addConstant("false", v, { addConstant(
.type = nBool, "false",
.doc = R"( v,
{
.type = nBool,
.doc = R"(
Primitive value. Primitive value.
It can be returned by It can be returned by
@ -226,12 +100,16 @@ void EvalState::createBaseEnv()
1 1
``` ```
)", )",
}); }
);
v.mkNull(); v.mkNull();
addConstant("null", v, { addConstant(
.type = nNull, "null",
.doc = R"( v,
{
.type = nNull,
.doc = R"(
Primitive value. Primitive value.
The name `null` is not special, and can be shadowed: The name `null` is not special, and can be shadowed:
@ -241,14 +119,18 @@ void EvalState::createBaseEnv()
1 1
``` ```
)", )",
}); }
);
if (!evalSettings.pureEval) { if (!evalSettings.pureEval) {
v.mkInt(time(0)); v.mkInt(time(0));
} }
addConstant("__currentTime", v, { addConstant(
.type = nInt, "__currentTime",
.doc = R"( v,
{
.type = nInt,
.doc = R"(
Return the [Unix time](https://en.wikipedia.org/wiki/Unix_time) at first evaluation. Return the [Unix time](https://en.wikipedia.org/wiki/Unix_time) at first evaluation.
Repeated references to that name will re-use the initially obtained value. Repeated references to that name will re-use the initially obtained value.
@ -267,14 +149,19 @@ void EvalState::createBaseEnv()
The [store path](@docroot@/glossary.md#gloss-store-path) of a derivation depending on `currentTime` will differ for each evaluation, unless both evaluate `builtins.currentTime` in the same second. The [store path](@docroot@/glossary.md#gloss-store-path) of a derivation depending on `currentTime` will differ for each evaluation, unless both evaluate `builtins.currentTime` in the same second.
)", )",
.impureOnly = true, .impureOnly = true,
}); }
);
if (!evalSettings.pureEval) if (!evalSettings.pureEval) {
v.mkString(evalSettings.getCurrentSystem()); v.mkString(evalSettings.getCurrentSystem());
addConstant("__currentSystem", v, { }
.type = nString, addConstant(
.doc = R"( "__currentSystem",
v,
{
.type = nString,
.doc = R"(
The value of the The value of the
[`eval-system`](@docroot@/command-ref/conf-file.md#conf-eval-system) [`eval-system`](@docroot@/command-ref/conf-file.md#conf-eval-system)
or else or else
@ -297,13 +184,17 @@ void EvalState::createBaseEnv()
"mips64-linux" "mips64-linux"
``` ```
)", )",
.impureOnly = true, .impureOnly = true,
}); }
);
v.mkString("2.18.3-lix"); v.mkString("2.18.3-lix");
addConstant("__nixVersion", v, { addConstant(
.type = nString, "__nixVersion",
.doc = R"( v,
{
.type = nString,
.doc = R"(
Legacy version of Nix. Always returns "2.18.3-lix" on Lix. Legacy version of Nix. Always returns "2.18.3-lix" on Lix.
Code in the Nix language should use other means of feature detection Code in the Nix language should use other means of feature detection
@ -314,12 +205,16 @@ void EvalState::createBaseEnv()
If the feature you want to write compatibility code for cannot be If the feature you want to write compatibility code for cannot be
detected by any means, please file a Lix bug. detected by any means, please file a Lix bug.
)", )",
}); }
);
v.mkString(store->storeDir); v.mkString(store->storeDir);
addConstant("__storeDir", v, { addConstant(
.type = nString, "__storeDir",
.doc = R"( v,
{
.type = nString,
.doc = R"(
Logical file system location of the [Nix store](@docroot@/glossary.md#gloss-store) currently in use. Logical file system location of the [Nix store](@docroot@/glossary.md#gloss-store) currently in use.
This value is determined by the `store` parameter in [Store URLs](@docroot@/command-ref/new-cli/nix3-help-stores.md): This value is determined by the `store` parameter in [Store URLs](@docroot@/command-ref/new-cli/nix3-help-stores.md):
@ -329,15 +224,19 @@ void EvalState::createBaseEnv()
"/blah" "/blah"
``` ```
)", )",
}); }
);
/* Legacy language version. /* Legacy language version.
* This is fixed at 6, and will never change in the future on Lix. * This is fixed at 6, and will never change in the future on Lix.
* A better language versioning construct needs to be built instead. */ * A better language versioning construct needs to be built instead. */
v.mkInt(6); v.mkInt(6);
addConstant("__langVersion", v, { addConstant(
.type = nInt, "__langVersion",
.doc = R"( v,
{
.type = nInt,
.doc = R"(
The legacy version of the Nix language. Always is `6` on Lix, The legacy version of the Nix language. Always is `6` on Lix,
matching Nix 2.18. matching Nix 2.18.
@ -349,7 +248,8 @@ void EvalState::createBaseEnv()
If the feature you want to write compatibility code for cannot be If the feature you want to write compatibility code for cannot be
detected by any means, please file a Lix bug. detected by any means, please file a Lix bug.
)", )",
}); }
);
// Miscellaneous // Miscellaneous
if (evalSettings.enableNativeCode) { if (evalSettings.enableNativeCode) {
@ -367,7 +267,7 @@ void EvalState::createBaseEnv()
addPrimOp({ addPrimOp({
.name = "__traceVerbose", .name = "__traceVerbose",
.args = { "e1", "e2" }, .args = {"e1", "e2"},
.arity = 2, .arity = 2,
.doc = R"( .doc = R"(
Evaluate *e1* and print its abstract syntax representation on standard Evaluate *e1* and print its abstract syntax representation on standard
@ -386,9 +286,12 @@ void EvalState::createBaseEnv()
attrs.alloc("prefix").mkString(i.prefix.s); attrs.alloc("prefix").mkString(i.prefix.s);
(v.listElems()[n++] = allocValue())->mkAttrs(attrs); (v.listElems()[n++] = allocValue())->mkAttrs(attrs);
} }
addConstant("__nixPath", v, { addConstant(
.type = nList, "__nixPath",
.doc = R"( v,
{
.type = nList,
.doc = R"(
The search path used to resolve angle bracket path lookups. The search path used to resolve angle bracket path lookups.
Angle bracket expressions can be Angle bracket expressions can be
@ -406,16 +309,18 @@ void EvalState::createBaseEnv()
builtins.findFile builtins.nixPath "nixpkgs" builtins.findFile builtins.nixPath "nixpkgs"
``` ```
)", )",
}); }
);
if (RegisterPrimOp::primOps) if (RegisterPrimOp::primOps) {
for (auto & primOp : *RegisterPrimOp::primOps) for (auto & primOp : *RegisterPrimOp::primOps) {
if (experimentalFeatureSettings.isEnabled(primOp.experimentalFeature)) if (experimentalFeatureSettings.isEnabled(primOp.experimentalFeature)) {
{
auto primOpAdjusted = primOp; auto primOpAdjusted = primOp;
primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity); primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity);
addPrimOp(std::move(primOpAdjusted)); addPrimOp(std::move(primOpAdjusted));
} }
}
}
/* Add a wrapper around the derivation primop that computes the /* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. `drvPath' and `outPath' attributes lazily.
@ -423,9 +328,13 @@ void EvalState::createBaseEnv()
Null docs because it is documented separately. Null docs because it is documented separately.
*/ */
auto vDerivation = allocValue(); auto vDerivation = allocValue();
addConstant("derivation", vDerivation, { addConstant(
.type = nFunction, "derivation",
}); vDerivation,
{
.type = nFunction,
}
);
/* Now that we've added all primops, sort the `builtins' set, /* Now that we've added all primops, sort the `builtins' set,
because attribute lookups expect it to be sorted. */ because attribute lookups expect it to be sorted. */
@ -436,12 +345,14 @@ void EvalState::createBaseEnv()
/* Note: we have to initialize the 'derivation' constant *after* /* Note: we have to initialize the 'derivation' constant *after*
building baseEnv/staticBaseEnv because it uses 'builtins'. */ building baseEnv/staticBaseEnv because it uses 'builtins'. */
char code[] = char code[] =
#include "primops/derivation.nix.gen.hh" #include "primops/derivation.nix.gen.hh"
// the parser needs two NUL bytes as terminators; one of them // the parser needs two NUL bytes as terminators; one of them
// is implied by being a C string. // is implied by being a C string.
"\0"; "\0";
eval(parse(code, sizeof(code), derivationInternal, {CanonPath::root}, staticBaseEnv), *vDerivation); eval(
parse(code, sizeof(code), derivationInternal, {CanonPath::root}, staticBaseEnv),
*vDerivation
);
} }
} }