aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2008-08-14 16:59:37 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2008-08-14 16:59:37 +0000
commitca07f3e37015fa85fbfc5afd868249d457e649c9 (patch)
tree9cc9408d37f9410952a0faf44b1b0f14236a9ae2 /src/libexpr/eval.cc
parent9279174dde3e1a450e63e866d2683352dd8238d3 (diff)
* Another experimental feature: a way to truly override attributes in
a rec. This will be very useful to allow end-user customisation of all-packages.nix, for instance globally overriding GCC or some other dependency. The // operator doesn't cut it: you could replace the "gcc" attribute, but all other attributes would continue to reference the original value due to the substitution semantics of rec. The syntax is a bit hacky but this is to allow backwards compatibility.
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index e79d42504..3da9cbc4d 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -170,16 +170,18 @@ static Expr substArgs(EvalState & state,
to attributes substituted with selection expressions on the
original set. E.g., e = `rec {x = f x y; y = x;}' becomes `{x = f
(e.x) (e.y); y = e.x;}'. */
-LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds))
+LocalNoInline(ATerm expandRec(EvalState & state, ATerm e, ATermList rbnds, ATermList nrbnds))
{
ATerm name;
Expr e2;
Pos pos;
+ Expr eOverrides = 0;
/* Create the substitution list. */
ATermMap subs(ATgetLength(rbnds) + ATgetLength(nrbnds));
for (ATermIterator i(rbnds); i; ++i) {
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
+ if (name == sOverrides) eOverrides = e2;
subs.set(name, makeSelect(e, name));
}
for (ATermIterator i(nrbnds); i; ++i) {
@@ -187,6 +189,22 @@ LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds))
subs.set(name, e2);
}
+ /* If the rec contains an attribute called `__overrides', then
+ evaluate it, and add the attributes in that set to the rec.
+ This allows overriding of recursive attributes, which is
+ otherwise not possible. (You can use the // operator to
+ replace an attribute, but other attributes in the rec will
+ still reference the original value, because that value has been
+ substituted into the bodies of the other attributes. Hence we
+ need __overrides.) */
+ ATermMap overrides;
+ if (eOverrides) {
+ eOverrides = evalExpr(state, eOverrides);
+ queryAllAttrs(overrides, overrides, false);
+ foreach (ATermMap::const_iterator, i, overrides)
+ subs.set(i->key, i->value);
+ }
+
Substitution subs_(0, &subs);
/* Create the non-recursive set. */
@@ -196,6 +214,10 @@ LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds))
as.set(name, makeAttrRHS(substitute(subs_, e2), pos));
}
+ if (eOverrides)
+ foreach (ATermMap::const_iterator, i, overrides)
+ as.set(i->key, makeAttrRHS(i->value, makeNoPos()));
+
/* Copy the non-recursive bindings. !!! inefficient */
for (ATermIterator i(nrbnds); i; ++i) {
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
@@ -667,7 +689,7 @@ Expr evalExpr2(EvalState & state, Expr e)
/* Mutually recursive sets. */
ATermList rbnds, nrbnds;
if (matchRec(e, rbnds, nrbnds))
- return expandRec(e, rbnds, nrbnds);
+ return expandRec(state, e, rbnds, nrbnds);
/* Conditionals. */
if (matchIf(e, e1, e2, e3))