diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index cede6db3c..5c4561f66 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -750,7 +750,7 @@ builtins.fetchurl {
files will be dlopened by Nix, allowing them to affect
execution through static initialization. In particular, these
plugins may construct static instances of RegisterPrimOp to
- add new primops to the expression language,
+ add new primops or constants to the expression language,
RegisterStoreImplementation to add new store implementations,
and RegisterCommand to add new subcommands to the
nix command. See the constructors for those
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 0b0a0f7b1..1f3bbc0a5 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -404,7 +404,7 @@ Path EvalState::toRealPath(const Path & path, const PathSet & context)
};
-void EvalState::addConstant(const string & name, Value & v)
+Value * EvalState::addConstant(const string & name, Value & v)
{
Value * v2 = allocValue();
*v2 = v;
@@ -412,12 +412,18 @@ void EvalState::addConstant(const string & name, Value & v)
baseEnv.values[baseEnvDispl++] = v2;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v2));
+ return v2;
}
Value * EvalState::addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp)
{
+ if (arity == 0) {
+ Value v;
+ primOp(*this, noPos, nullptr, v);
+ return addConstant(name, v);
+ }
Value * v = allocValue();
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
Symbol sym = symbols.create(name2);
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 9e3d30d95..51905d7e1 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -210,7 +210,7 @@ private:
void createBaseEnv();
- void addConstant(const string & name, Value & v);
+ Value * addConstant(const string & name, Value & v);
Value * addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp);
diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh
index 39d23b04a..31bf3f84f 100644
--- a/src/libexpr/primops.hh
+++ b/src/libexpr/primops.hh
@@ -9,6 +9,9 @@ struct RegisterPrimOp
{
typedef std::vector> PrimOps;
static PrimOps * primOps;
+ /* You can register a constant by passing an arity of 0. fun
+ will get called during EvalState initialization, so there
+ may be primops not yet added and builtins is not yet sorted. */
RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun);
};
diff --git a/tests/plugins.sh b/tests/plugins.sh
index 6d18d1da0..23caf04f3 100644
--- a/tests/plugins.sh
+++ b/tests/plugins.sh
@@ -2,6 +2,6 @@ source common.sh
set -o pipefail
-res=$(nix eval '(builtins.constNull true)' --option plugin-files $PWD/plugins/plugintest.so)
+res=$(nix eval '(builtins.anotherNull)' --option plugin-files $PWD/plugins/plugintest.so)
[ "$res"x = "nullx" ]
diff --git a/tests/plugins/plugintest.cc b/tests/plugins/plugintest.cc
index f788c4814..6b5e6d7cd 100644
--- a/tests/plugins/plugintest.cc
+++ b/tests/plugins/plugintest.cc
@@ -2,9 +2,9 @@
using namespace nix;
-static void prim_constNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
+static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
{
mkNull(v);
}
-static RegisterPrimOp r("constNull", 1, prim_constNull);
+static RegisterPrimOp r("anotherNull", 0, prim_anotherNull);