aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-08-25 14:06:01 +0200
committerEelco Dolstra <edolstra@gmail.com>2020-08-25 14:06:01 +0200
commit7a02865b94f107de1c1ef797b89d45ecd3f01cf1 (patch)
tree8262f1c7aba5870569a9ed7ffd20e53723287b51
parentf53b5f10585b1d4c939e45faf0dd2f4dacbca013 (diff)
Move import docs
-rw-r--r--doc/manual/src/expressions/builtins-prefix.md53
-rw-r--r--src/libexpr/primops.cc93
-rwxr-xr-xtests/function-trace.sh12
3 files changed, 80 insertions, 78 deletions
diff --git a/doc/manual/src/expressions/builtins-prefix.md b/doc/manual/src/expressions/builtins-prefix.md
index ae3bb150c..0f7c3d32f 100644
--- a/doc/manual/src/expressions/builtins-prefix.md
+++ b/doc/manual/src/expressions/builtins-prefix.md
@@ -13,56 +13,3 @@ For instance, `derivation` is also available as `builtins.derivation`.
`derivation` is described in [its own section](derivations.md).
- - `import` *path*; `builtins.import` *path*
-
- Load, parse and return the Nix expression in the file *path*. If
- *path* is a directory, the file ` default.nix ` in that directory
- is loaded. Evaluation aborts if the file doesn’t exist or contains
- an incorrect Nix expression. `import` implements Nix’s module
- system: you can put any Nix expression (such as a set or a
- function) in a separate file, and use it from Nix expressions in
- other files.
-
- > **Note**
- >
- > Unlike some languages, `import` is a regular function in Nix.
- > Paths using the angle bracket syntax (e.g., `import` *\<foo\>*)
- > are [normal path values](language-values.md).
-
- A Nix expression loaded by `import` must not contain any *free
- variables* (identifiers that are not defined in the Nix expression
- itself and are not built-in). Therefore, it cannot refer to
- variables that are in scope at the call site. For instance, if you
- have a calling expression
-
- ```nix
- rec {
- x = 123;
- y = import ./foo.nix;
- }
- ```
-
- then the following `foo.nix` will give an error:
-
- ```nix
- x + 456
- ```
-
- since `x` is not in scope in `foo.nix`. If you want `x` to be
- available in `foo.nix`, you should pass it as a function argument:
-
- ```nix
- rec {
- x = 123;
- y = import ./foo.nix x;
- }
- ```
-
- and
-
- ```nix
- x: x + 456
- ```
-
- (The function argument doesn’t have to be called `x` in `foo.nix`;
- any name would work.)
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 2d3433200..821cf0782 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -74,10 +74,10 @@ void EvalState::realiseContext(const PathSet & context)
/* Load and evaluate an expression from path specified by the
argument. */
-static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args, Value & v)
+static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v)
{
PathSet context;
- Path path = state.coerceToPath(pos, *args[1], context);
+ Path path = state.coerceToPath(pos, vPath, context);
try {
state.realiseContext(context);
@@ -99,6 +99,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
return std::nullopt;
return storePath;
};
+
if (auto optStorePath = isValidDerivationInStore()) {
auto storePath = *optStorePath;
Derivation drv = readDerivation(*state.store, realPath, Derivation::nameFromPath(storePath));
@@ -133,17 +134,18 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
mkApp(v, **fun, w);
state.forceAttrs(v, pos);
} else {
- state.forceAttrs(*args[0]);
- if (args[0]->attrs->empty())
+ if (!vScope)
state.evalFile(realPath, v);
else {
- Env * env = &state.allocEnv(args[0]->attrs->size());
+ state.forceAttrs(*vScope);
+
+ Env * env = &state.allocEnv(vScope->attrs->size());
env->up = &state.baseEnv;
StaticEnv staticEnv(false, &state.staticBaseEnv);
unsigned int displ = 0;
- for (auto & attr : *args[0]->attrs) {
+ for (auto & attr : *vScope->attrs) {
staticEnv.vars[attr.name] = displ;
env->values[displ++] = attr.value;
}
@@ -156,6 +158,77 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
}
}
+static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info {
+ .name = "scopedImport",
+ .arity = 2,
+ .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
+ {
+ import(state, pos, *args[1], args[0], v);
+ }
+});
+
+static RegisterPrimOp primop_import({
+ .name = "import",
+ .args = {"path"},
+ .doc = R"(
+ Load, parse and return the Nix expression in the file *path*. If
+ *path* is a directory, the file ` default.nix ` in that directory
+ is loaded. Evaluation aborts if the file doesn’t exist or contains
+ an incorrect Nix expression. `import` implements Nix’s module
+ system: you can put any Nix expression (such as a set or a
+ function) in a separate file, and use it from Nix expressions in
+ other files.
+
+ > **Note**
+ >
+ > Unlike some languages, `import` is a regular function in Nix.
+ > Paths using the angle bracket syntax (e.g., `import` *\<foo\>*)
+ > are [normal path values](language-values.md).
+
+ A Nix expression loaded by `import` must not contain any *free
+ variables* (identifiers that are not defined in the Nix expression
+ itself and are not built-in). Therefore, it cannot refer to
+ variables that are in scope at the call site. For instance, if you
+ have a calling expression
+
+ ```nix
+ rec {
+ x = 123;
+ y = import ./foo.nix;
+ }
+ ```
+
+ then the following `foo.nix` will give an error:
+
+ ```nix
+ x + 456
+ ```
+
+ since `x` is not in scope in `foo.nix`. If you want `x` to be
+ available in `foo.nix`, you should pass it as a function argument:
+
+ ```nix
+ rec {
+ x = 123;
+ y = import ./foo.nix x;
+ }
+ ```
+
+ and
+
+ ```nix
+ x: x + 456
+ ```
+
+ (The function argument doesn’t have to be called `x` in `foo.nix`;
+ any name would work.)
+ )",
+ .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
+ {
+ import(state, pos, *args[0], nullptr, v);
+ }
+});
+
/* Want reasonable symbol names, so extern C */
/* !!! Should we pass the Pos or the file name too? */
extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
@@ -3429,12 +3502,6 @@ void EvalState::createBaseEnv()
addConstant("__langVersion", v);
// Miscellaneous
- auto vScopedImport = addPrimOp("scopedImport", 2, prim_scopedImport);
- Value * v2 = allocValue();
- mkAttrs(*v2, 0);
- mkApp(v, *vScopedImport, *v2);
- forceValue(v);
- addConstant("import", v);
if (evalSettings.enableNativeCode) {
addPrimOp("__importNative", 2, prim_importNative);
addPrimOp("__exec", 1, prim_exec);
@@ -3444,7 +3511,7 @@ void EvalState::createBaseEnv()
mkList(v, searchPath.size());
int n = 0;
for (auto & i : searchPath) {
- v2 = v.listElems()[n++] = allocValue();
+ auto v2 = v.listElems()[n++] = allocValue();
mkAttrs(*v2, 2);
mkString(*allocAttr(*v2, symbols.create("path")), i.second);
mkString(*allocAttr(*v2, symbols.create("prefix")), i.first);
diff --git a/tests/function-trace.sh b/tests/function-trace.sh
index 182a4d5c2..3b7f364e3 100755
--- a/tests/function-trace.sh
+++ b/tests/function-trace.sh
@@ -32,8 +32,6 @@ expect_trace() {
# failure inside a tryEval
expect_trace 'builtins.tryEval (throw "example")' "
-function-trace entered undefined position at
-function-trace exited undefined position at
function-trace entered (string):1:1 at
function-trace entered (string):1:19 at
function-trace exited (string):1:19 at
@@ -42,32 +40,24 @@ function-trace exited (string):1:1 at
# Missing argument to a formal function
expect_trace '({ x }: x) { }' "
-function-trace entered undefined position at
-function-trace exited undefined position at
function-trace entered (string):1:1 at
function-trace exited (string):1:1 at
"
# Too many arguments to a formal function
expect_trace '({ x }: x) { x = "x"; y = "y"; }' "
-function-trace entered undefined position at
-function-trace exited undefined position at
function-trace entered (string):1:1 at
function-trace exited (string):1:1 at
"
# Not enough arguments to a lambda
expect_trace '(x: y: x + y) 1' "
-function-trace entered undefined position at
-function-trace exited undefined position at
function-trace entered (string):1:1 at
function-trace exited (string):1:1 at
"
# Too many arguments to a lambda
expect_trace '(x: x) 1 2' "
-function-trace entered undefined position at
-function-trace exited undefined position at
function-trace entered (string):1:1 at
function-trace exited (string):1:1 at
function-trace entered (string):1:1 at
@@ -76,8 +66,6 @@ function-trace exited (string):1:1 at
# Not a function
expect_trace '1 2' "
-function-trace entered undefined position at
-function-trace exited undefined position at
function-trace entered (string):1:1 at
function-trace exited (string):1:1 at
"