diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index dfc565b4..bc4db2d8 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -7,6 +7,30 @@ #include "nixexpr-ast.hh" +static Expr primBuiltins(EvalState & state, const ATermVector & args) +{ + /* Return an attribute set containing all primops. This allows + Nix expressions to test for new primops and take appropriate + action if they're not available. For instance, rather than + calling a primop `foo' directly, they could say `if builtins ? + foo then builtins.foo ... else ...'. */ + + ATermMap builtins(128); + + for (ATermMap::const_iterator i = state.primOps.begin(); + i != state.primOps.end(); ++i) + { + string name = aterm2String(i->key); + if (string(name, 0, 2) == "__") + name = string(name, 2); + /* !!! should use makePrimOp here, I guess. */ + builtins.set(toATerm(name), makeAttrRHS(makeVar(i->key), makeNoPos())); + } + + return makeAttrs(builtins); +} + + /* Load and evaluate an expression from path specified by the argument. */ static Expr primImport(EvalState & state, const ATermVector & args) @@ -660,6 +684,8 @@ static Expr primRelativise(EvalState & state, const ATermVector & args) void EvalState::addPrimOps() { + addPrimOp("builtins", 0, primBuiltins); + addPrimOp("true", 0, primTrue); addPrimOp("false", 0, primFalse); addPrimOp("null", 0, primNull); diff --git a/tests/lang/eval-okay-builtins.exp b/tests/lang/eval-okay-builtins.exp new file mode 100644 index 00000000..f4f3ba81 --- /dev/null +++ b/tests/lang/eval-okay-builtins.exp @@ -0,0 +1 @@ +Path("/foo") diff --git a/tests/lang/eval-okay-builtins.nix b/tests/lang/eval-okay-builtins.nix new file mode 100644 index 00000000..e9d65e88 --- /dev/null +++ b/tests/lang/eval-okay-builtins.nix @@ -0,0 +1,12 @@ +assert builtins ? currentSystem; +assert !builtins ? __currentSystem; + +let { + + x = if builtins ? dirOf then builtins.dirOf /foo/bar else ""; + + y = if builtins ? fnord then builtins.fnord "foo" else ""; + + body = x + y; + +}