diff --git a/corepkgs/buildenv/builder.pl.in b/corepkgs/buildenv/builder.pl.in
index e53b383f1..d6dd2f4cf 100755
--- a/corepkgs/buildenv/builder.pl.in
+++ b/corepkgs/buildenv/builder.pl.in
@@ -27,7 +27,7 @@ sub createLinks {
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/log$/)
{
- # Do noting.
+ # Do nothing.
}
elsif (-d $srcFile) {
diff --git a/doc/manual/package-management.xml b/doc/manual/package-management.xml
index 470cb80a0..b717844b1 100644
--- a/doc/manual/package-management.xml
+++ b/doc/manual/package-management.xml
@@ -17,18 +17,12 @@ available for installation.
In Nix, different users can have different views
on the set of installed applications. That is, there might be lots of
applications present on the system (possibly in many different
-versions), but users can have a specific selection of those
-active — where active just means that it appears
-in a directory in the user's PATH.
-
-Such a view on the set of installed applications is called a
-user environment, which is just a directory tree
-consisting of symlinks to the files of the active applications. In
-Nix, operations such as upgrading or removing components never
-overwrite or remove the files of those components, and they don't even
-touch the user environments that point to them. Rather, they cause a
-new user environment to be constructed based on
-the old one.
+versions), but users can have a specific selection of those active —
+where active just means that it appears in a directory
+in the user's PATH. Such a view on the set of
+installed applications is called a user
+environment, which is just a directory tree consisting of
+symlinks to the files of the active applications.
Components are installed from a set of Nix
expressions that tell Nix how to build those components,
@@ -168,7 +162,21 @@ set.Profiles
-Bla
+In Nix, operations such as upgrading or removing components
+never overwrite or remove the files of those components, and they
+don't even touch the user environments that point to them. Rather,
+they cause a new user environment to be
+constructed based on the old one. This is illustrated in Figure
+bla.
+
+
+
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 89cc8254d..215692aeb 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -230,7 +230,7 @@ Expr evalExpr2(EvalState & state, Expr e)
try {
return evalExpr(state, substArgs(e4, formals, e2));
} catch (Error & e) {
- throw Error(format("while evaluating function at %1%:\n%2%")
+ throw Error(format("while evaluating the function at %1%:\n%2%")
% showPos(pos) % e.msg());
}
}
@@ -241,7 +241,7 @@ Expr evalExpr2(EvalState & state, Expr e)
subs.set(name, e2);
return evalExpr(state, substitute(subs, e4));
} catch (Error & e) {
- throw Error(format("while evaluating function at %1%:\n%2%")
+ throw Error(format("while evaluating the function at %1%:\n%2%")
% showPos(pos) % e.msg());
}
}
@@ -258,7 +258,7 @@ Expr evalExpr2(EvalState & state, Expr e)
try {
return evalExpr(state, a);
} catch (Error & e) {
- throw Error(format("while evaluating attribute `%1%' at %2%:\n%3%")
+ throw Error(format("while evaluating the attribute `%1%' at %2%:\n%3%")
% s1 % showPos(pos) % e.msg());
}
}
@@ -283,6 +283,26 @@ Expr evalExpr2(EvalState & state, Expr e)
return evalExpr(state, e2);
}
+ /* Withs. */
+ if (atMatch(m, e) >> "With" >> e1 >> e2 >> pos) {
+ ATermMap attrs;
+ try {
+ e1 = evalExpr(state, e1);
+ queryAllAttrs(e1, attrs);
+ } catch (Error & e) {
+ throw Error(format("while evaluating the `with' definitions at %1%:\n%2%")
+ % showPos(pos) % e.msg());
+ }
+ try {
+ e2 = substitute(attrs, e2);
+ checkVarDefs(state.primOps, e2);
+ return evalExpr(state, e2);
+ } catch (Error & e) {
+ throw Error(format("while evaluating the `with' body at %1%:\n%2%")
+ % showPos(pos) % e.msg());
+ }
+ }
+
/* Generic equality. */
if (atMatch(m, e) >> "OpEq" >> e1 >> e2)
return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
@@ -357,7 +377,7 @@ Expr evalFile(EvalState & state, const Path & path)
try {
return evalExpr(state, e);
} catch (Error & e) {
- throw Error(format("while evaluating file `%1%':\n%2%")
+ throw Error(format("while evaluating the file `%1%':\n%2%")
% path % e.msg());
}
}
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 9637fd304..78d08d072 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -48,6 +48,7 @@ if { return IF; }
then { return THEN; }
else { return ELSE; }
assert { return ASSERT; }
+with { return WITH; }
let { return LET; }
rec { return REC; }
inherit { return INHERIT; }
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index dec734e46..78f89db5e 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -296,7 +296,7 @@ void checkVarDefs(const ATermMap & defs, Expr e)
ATMatcher m;
ATerm name;
ATermList formals;
- ATerm body;
+ ATerm with, body;
ATermList rbnds, nrbnds;
if (atMatch(m, e) >> "Var" >> name) {
@@ -340,6 +340,13 @@ void checkVarDefs(const ATermMap & defs, Expr e)
}
checkVarDefs(defs2, (ATerm) rbnds);
}
+
+ else if (atMatch(m, e) >> "With" >> with >> body) {
+ /* We can't check the body without evaluating the definitions
+ (which is an arbitrary expression), so we don't do that
+ here but only when actually evaluating the `with'. */
+ checkVarDefs(defs, with);
+ }
else if (ATgetType(e) == AT_APPL) {
int arity = ATgetArity(ATgetAFun(e));
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 347516f69..88ee8326b 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -41,11 +41,11 @@ ATerm makePos(YYLTYPE * loc, void * data)
ATermList ts;
}
-%type start expr expr_function expr_assert expr_if expr_op
+%type start expr expr_function expr_if expr_op
%type expr_app expr_select expr_simple bind inheritsrc formal
%type binds ids expr_list formals
%token ID INT STR PATH URI
-%token IF THEN ELSE ASSERT LET REC INHERIT EQ NEQ AND OR IMPL
+%token IF THEN ELSE ASSERT WITH LET REC INHERIT EQ NEQ AND OR IMPL
%nonassoc IMPL
%left OR
@@ -67,12 +67,10 @@ expr_function
{ $$ = ATmake("Function(, , )", $2, $5, CUR_POS); }
| ID ':' expr_function
{ $$ = ATmake("Function1(, , )", $1, $3, CUR_POS); }
- | expr_assert
- ;
-
-expr_assert
- : ASSERT expr ';' expr_assert
+ | ASSERT expr ';' expr_function
{ $$ = ATmake("Assert(, , )", $2, $4, CUR_POS); }
+ | WITH expr ';' expr_function
+ { $$ = ATmake("With(, , )", $2, $4, CUR_POS); }
| expr_if
;
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 070ed1b54..938d9bb8c 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -205,7 +205,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args)
try {
processBinding(state, value, ne, ss);
} catch (Error & e) {
- throw Error(format("while processing derivation attribute `%1%' at %2%:\n%3%")
+ throw Error(format("while processing the derivation attribute `%1%' at %2%:\n%3%")
% key % showPos(pos) % e.msg());
}