From 081f14a169d36243f97263acb41fb108af243619 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Thu, 8 Feb 2018 13:00:53 -0500 Subject: [PATCH] Allow using RegisterPrimop to define constants. This enables plugins to add new constants, as well as new primops. --- doc/manual/command-ref/conf-file.xml | 2 +- src/libexpr/eval.cc | 8 +++++++- src/libexpr/eval.hh | 2 +- src/libexpr/primops.hh | 3 +++ tests/plugins.sh | 2 +- tests/plugins/plugintest.cc | 4 ++-- 6 files changed, 15 insertions(+), 6 deletions(-) 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);