about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-03-31T15·38+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-03-31T15·38+0000
commit3d94be61ea562dea2098b6570f711386179913ef (patch)
tree9afd60cf782d5824efc4bafba98af1ee6af937f4
parent51876789131e81dca9807c00773158160c3824c2 (diff)
* Implemented derivations.
-rw-r--r--src/libexpr/eval.cc41
-rw-r--r--src/libexpr/eval.hh9
-rw-r--r--src/libexpr/get-drvs.cc143
-rw-r--r--src/libexpr/get-drvs.hh15
-rw-r--r--src/libexpr/primops.cc150
-rw-r--r--src/nix-instantiate/nix-instantiate.cc19
6 files changed, 184 insertions, 193 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 7f0adb2c4cad..0296afe60155 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -261,6 +261,14 @@ void EvalState::mkAttrs(Value & v)
 }
 
 
+void EvalState::cloneAttrs(Value & src, Value & dst)
+{
+    mkAttrs(dst);
+    foreach (Bindings::iterator, i, *src.attrs)
+        (*dst.attrs)[i->first] = i->second; // !!! sharing?
+}
+
+
 void EvalState::evalFile(const Path & path, Value & v)
 {
     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
@@ -488,17 +496,14 @@ void EvalState::eval(Env & env, Expr e, Value & v)
 
     /* Attribute set update (//). */
     else if (matchOpUpdate(e, e1, e2)) {
-        mkAttrs(v);
-        
         Value v2;
-        eval(env, e2, v2);
-        foreach (Bindings::iterator, i, *v2.attrs)
-            (*v.attrs)[i->first] = i->second;
-        
         eval(env, e1, v2);
+        
+        cloneAttrs(v2, v);
+        
+        eval(env, e2, v2);
         foreach (Bindings::iterator, i, *v2.attrs)
-            if (v.attrs->find(i->first) == v.attrs->end())
-                (*v.attrs)[i->first] = i->second;
+            (*v.attrs)[i->first] = i->second; // !!! sharing
     }
 
     /* Attribute existence test (?). */
@@ -673,6 +678,15 @@ int EvalState::forceInt(Value & v)
 }
 
 
+bool EvalState::forceBool(Value & v)
+{
+    forceValue(v);
+    if (v.type != tBool)
+        throw TypeError(format("value is %1% while a Boolean was expected") % showType(v));
+    return v.boolean;
+}
+
+
 void EvalState::forceAttrs(Value & v)
 {
     forceValue(v);
@@ -697,15 +711,22 @@ void EvalState::forceFunction(Value & v)
 }
 
 
-string EvalState::forceStringNoCtx(Value & v)
+string EvalState::forceString(Value & v)
 {
     forceValue(v);
     if (v.type != tString)
         throw TypeError(format("value is %1% while a string was expected") % showType(v));
+    return string(v.string.s);
+}
+
+
+string EvalState::forceStringNoCtx(Value & v)
+{
+    string s = forceString(v);
     if (v.string.context)
         throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
             % v.string.s % v.string.context[0]);
-    return string(v.string.s);
+    return s;
 }
 
 
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 198d936b9738..eba97dd73756 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -109,7 +109,6 @@ void mkString(Value & v, const string & s, const PathSet & context = PathSet());
 void mkPath(Value & v, const char * s);
 
 
-typedef std::map<Path, PathSet> DrvRoots;
 typedef std::map<Path, Hash> DrvHashes;
 
 /* Cache for calls to addToStore(); maps source paths to the store
@@ -124,8 +123,10 @@ std::ostream & operator << (std::ostream & str, Value & v);
 
 class EvalState 
 {
-    DrvRoots drvRoots;
+public:
     DrvHashes drvHashes; /* normalised derivation hashes */
+
+private:
     SrcToStore srcToStore; 
 
     unsigned long nrValues;
@@ -164,9 +165,11 @@ public:
 
     /* Force `v', and then verify that it has the expected type. */
     int forceInt(Value & v);
+    bool forceBool(Value & v);
     void forceAttrs(Value & v);
     void forceList(Value & v);
     void forceFunction(Value & v); // either lambda or primop
+    string forceString(Value & v);
     string forceStringNoCtx(Value & v);
 
     /* String coercion.  Converts strings, paths and derivations to a
@@ -209,6 +212,8 @@ public:
     void mkList(Value & v, unsigned int length);
     void mkAttrs(Value & v);
 
+    void cloneAttrs(Value & src, Value & dst);
+
     /* Print statistics. */
     void printStats();
 };
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 26ce6e71cf74..5ff77ff65695 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -6,25 +6,18 @@
 namespace nix {
 
 
-#if 0
 string DrvInfo::queryDrvPath(EvalState & state) const
 {
     if (drvPath == "") {
-        Expr a = attrs->get(toATerm("drvPath"));
-
-        /* Backwards compatibility hack with user environments made by
-           Nix <= 0.10: these contain illegal Path("") expressions. */
-        ATerm t;
-        if (a && matchPath(evalExpr(state, a), t))
-            return aterm2String(t);
-        
+        Bindings::iterator i = attrs->find(toATerm("drvPath"));
         PathSet context;
-        (string &) drvPath = a ? coerceToPath(state, a, context) : "";
+        (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
     }
     return drvPath;
 }
 
 
+#if 0
 string DrvInfo::queryOutPath(EvalState & state) const
 {
     if (outPath == "") {
@@ -102,54 +95,47 @@ void DrvInfo::setMetaInfo(const MetaInfo & meta)
     }
     attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
 }
+#endif
 
 
-/* Cache for already evaluated derivations.  Usually putting ATerms in
-   a STL container is unsafe (they're not scanning for GC roots), but
-   here it doesn't matter; everything in this set is reachable from
-   the stack as well. */
-typedef set<Expr> Exprs;
+/* Cache for already considered values. */
+typedef set<Value *> Values;
 
 
-/* Evaluate expression `e'.  If it evaluates to an attribute set of
-   type `derivation', then put information about it in `drvs' (unless
-   it's already in `doneExprs').  The result boolean indicates whether
-   it makes sense for the caller to recursively search for derivations
-   in `e'. */
-static bool getDerivation(EvalState & state, Expr e,
-    const string & attrPath, DrvInfos & drvs, Exprs & doneExprs)
+/* Evaluate value `v'.  If it evaluates to an attribute set of type
+   `derivation', then put information about it in `drvs' (unless it's
+   already in `doneExprs').  The result boolean indicates whether it
+   makes sense for the caller to recursively search for derivations in
+   `v'. */
+static bool getDerivation(EvalState & state, Value & v,
+    const string & attrPath, DrvInfos & drvs, Values & doneValues)
 {
     try {
-        
-        ATermList es;
-        e = evalExpr(state, e);
-        if (!matchAttrs(e, es)) return true;
+        state.forceValue(v);
+        if (v.type != tAttrs) return true;
 
-        boost::shared_ptr<ATermMap> attrs(new ATermMap());
-        queryAllAttrs(e, *attrs, false);
-        
-        Expr a = attrs->get(toATerm("type"));
-        if (!a || evalStringNoCtx(state, a) != "derivation") return true;
+        Bindings::iterator i = v.attrs->find(toATerm("type"));
+        if (i == v.attrs->end() || state.forceStringNoCtx(i->second) != "derivation") return true;
 
         /* Remove spurious duplicates (e.g., an attribute set like
            `rec { x = derivation {...}; y = x;}'. */
-        if (doneExprs.find(e) != doneExprs.end()) return false;
-        doneExprs.insert(e);
+        if (doneValues.find(&v) != doneValues.end()) return false;
+        doneValues.insert(&v);
 
         DrvInfo drv;
     
-        a = attrs->get(toATerm("name"));
+        i = v.attrs->find(toATerm("name"));
         /* !!! We really would like to have a decent back trace here. */
-        if (!a) throw TypeError("derivation name missing");
-        drv.name = evalStringNoCtx(state, a);
+        if (i == v.attrs->end()) throw TypeError("derivation name missing");
+        drv.name = state.forceStringNoCtx(i->second);
 
-        a = attrs->get(toATerm("system"));
-        if (!a)
+        i = v.attrs->find(toATerm("system"));
+        if (i == v.attrs->end())
             drv.system = "unknown";
         else
-            drv.system = evalStringNoCtx(state, a);
+            drv.system = state.forceStringNoCtx(i->second);
 
-        drv.attrs = attrs;
+        drv.attrs = v.attrs;
 
         drv.attrPath = attrPath;
 
@@ -162,11 +148,11 @@ static bool getDerivation(EvalState & state, Expr e,
 }
 
 
-bool getDerivation(EvalState & state, Expr e, DrvInfo & drv)
+bool getDerivation(EvalState & state, Value & v, DrvInfo & drv)
 {
-    Exprs doneExprs;
+    Values doneValues;
     DrvInfos drvs;
-    getDerivation(state, e, "", drvs, doneExprs);
+    getDerivation(state, v, "", drvs, doneValues);
     if (drvs.size() != 1) return false;
     drv = drvs.front();
     return true;
@@ -179,85 +165,72 @@ static string addToPath(const string & s1, const string & s2)
 }
 
 
-static void getDerivations(EvalState & state, Expr e,
+static void getDerivations(EvalState & state, Value & v,
     const string & pathPrefix, const ATermMap & autoArgs,
-    DrvInfos & drvs, Exprs & doneExprs)
+    DrvInfos & drvs, Values & doneValues)
 {
-    e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs));
-
+    // !!! autoCallFunction(evalExpr(state, e), autoArgs)
+    
     /* Process the expression. */
-    ATermList es;
     DrvInfo drv;
 
-    if (!getDerivation(state, e, pathPrefix, drvs, doneExprs))
-        return;
+    if (!getDerivation(state, v, pathPrefix, drvs, doneValues)) ;
 
-    if (matchAttrs(e, es)) {
-        ATermMap drvMap(ATgetLength(es));
-        queryAllAttrs(e, drvMap);
+    else if (v.type == tAttrs) {
 
         /* !!! undocumented hackery to support combining channels in
            nix-env.cc. */
-        bool combineChannels = drvMap.get(toATerm("_combineChannels"));
+        bool combineChannels = v.attrs->find(toATerm("_combineChannels")) != v.attrs->end();
 
         /* Consider the attributes in sorted order to get more
            deterministic behaviour in nix-env operations (e.g. when
            there are names clashes between derivations, the derivation
            bound to the attribute with the "lower" name should take
            precedence). */
-        typedef std::map<string, Expr> AttrsSorted;
-        AttrsSorted attrsSorted;
-        foreach (ATermMap::const_iterator, i, drvMap)
-            attrsSorted[aterm2String(i->key)] = i->value;
-
-        foreach (AttrsSorted::iterator, i, attrsSorted) {
-            startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first);
-            string pathPrefix2 = addToPath(pathPrefix, i->first);
+        StringSet attrs;
+        foreach (Bindings::iterator, i, *v.attrs)
+            attrs.insert(aterm2String(i->first));
+
+        foreach (StringSet::iterator, i, attrs) {
+            startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i);
+            string pathPrefix2 = addToPath(pathPrefix, *i);
+            Value & v2((*v.attrs)[toATerm(*i)]);
             if (combineChannels)
-                getDerivations(state, i->second, pathPrefix2, autoArgs, drvs, doneExprs);
-            else if (getDerivation(state, i->second, pathPrefix2, drvs, doneExprs)) {
+                getDerivations(state, v2, pathPrefix2, autoArgs, drvs, doneValues);
+            else if (getDerivation(state, v2, pathPrefix2, drvs, doneValues)) {
                 /* If the value of this attribute is itself an
                    attribute set, should we recurse into it?  => Only
                    if it has a `recurseForDerivations = true'
                    attribute. */
-                ATermList es;
-                Expr e = evalExpr(state, i->second), e2;
-                if (matchAttrs(e, es)) {
-                    ATermMap attrs(ATgetLength(es));
-                    queryAllAttrs(e, attrs, false);
-                    if (((e2 = attrs.get(toATerm("recurseForDerivations")))
-                            && evalBool(state, e2)))
-                        getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
+                if (v2.type == tAttrs) {
+                    Bindings::iterator j = v2.attrs->find(toATerm("recurseForDerivations"));
+                    if (j != v2.attrs->end() && state.forceBool(j->second))
+                        getDerivations(state, v2, pathPrefix2, autoArgs, drvs, doneValues);
                 }
             }
         }
-        
-        return;
     }
 
-    if (matchList(e, es)) {
-        int n = 0;
-        for (ATermIterator i(es); i; ++i, ++n) {
+    else if (v.type == tList) {
+        for (unsigned int n = 0; n < v.list.length; ++n) {
             startNest(nest, lvlDebug,
                 format("evaluating list element"));
             string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
-            if (getDerivation(state, *i, pathPrefix2, drvs, doneExprs))
-                getDerivations(state, *i, pathPrefix2, autoArgs, drvs, doneExprs);
+            if (getDerivation(state, v.list.elems[n], pathPrefix2, drvs, doneValues))
+                getDerivations(state, v.list.elems[n], pathPrefix2, autoArgs, drvs, doneValues);
         }
-        return;
     }
 
-    throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
+    else throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
 }
 
 
-void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
+void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
     const ATermMap & autoArgs, DrvInfos & drvs)
 {
-    Exprs doneExprs;
-    getDerivations(state, e, pathPrefix, autoArgs, drvs, doneExprs);
+    Values doneValues;
+    getDerivations(state, v, pathPrefix, autoArgs, drvs, doneValues);
 }
-#endif
 
  
 }
diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh
index b56f54711899..733f2020129b 100644
--- a/src/libexpr/get-drvs.hh
+++ b/src/libexpr/get-drvs.hh
@@ -35,10 +35,8 @@ public:
     string attrPath; /* path towards the derivation */
     string system;
 
-    /* !!! these should really be hidden, and setMetaInfo() should
-       make a copy since the ATermMap can be shared between multiple
-       DrvInfos. */
-    boost::shared_ptr<ATermMap> attrs;
+    /* !!! make this private */
+    Bindings * attrs;
 
     string queryDrvPath(EvalState & state) const;
     string queryOutPath(EvalState & state) const;
@@ -62,12 +60,11 @@ public:
 typedef list<DrvInfo> DrvInfos;
 
 
-/* Evaluate expression `e'.  If it evaluates to a derivation, store
-   information about the derivation in `drv' and return true.
-   Otherwise, return false. */
-bool getDerivation(EvalState & state, Expr e, DrvInfo & drv);
+/* If value `v' denotes a derivation, store information about the
+   derivation in `drv' and return true.  Otherwise, return false. */
+bool getDerivation(EvalState & state, Value & v, DrvInfo & drv);
 
-void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
+void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
     const ATermMap & autoArgs, DrvInfos & drvs);
 
  
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 4b7e37e612af..31914a65dd18 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -207,6 +207,7 @@ static void prim_trace(EvalState & state, Value * * args, Value & v)
         printMsg(lvlError, format("trace: %1%") % e);
     return evalExpr(state, args[1]);
 }
+#endif
 
 
 /*************************************************************
@@ -282,24 +283,21 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
 {
     startNest(nest, lvlVomit, "evaluating derivation");
 
-    ATermMap attrs;
-    queryAllAttrs(evalExpr(state, args[0]), attrs, true);
+    state.forceAttrs(*args[0]);
 
-    /* Figure out the name already (for stack backtraces). */
-    ATerm posDrvName;
-    Expr eDrvName = attrs.get(toATerm("name"));
-    if (!eDrvName)
+    /* Figure out the name first (for stack backtraces). */
+    Bindings::iterator attr = args[0]->attrs->find(toATerm("name"));
+    if (attr == args[0]->attrs->end())
         throw EvalError("required attribute `name' missing");
-    if (!matchAttrRHS(eDrvName, eDrvName, posDrvName)) abort();
     string drvName;
     try {        
-        drvName = evalStringNoCtx(state, eDrvName);
+        drvName = state.forceStringNoCtx(attr->second);
     } catch (Error & e) {
-        e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n")
-            % showPos(posDrvName));
+        e.addPrefix(format("while evaluating the derivation attribute `name' at <SOMEWHERE>:\n"));
+        // !!! % showPos(posDrvName));
         throw;
     }
-
+    
     /* Build the derivation expression by processing the attributes. */
     Derivation drv;
     
@@ -308,12 +306,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
     string outputHash, outputHashAlgo;
     bool outputHashRecursive = false;
 
-    for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
-        string key = aterm2String(i->key);
-        ATerm value;
-        Expr pos;
-        ATerm rhs = i->value;
-        if (!matchAttrRHS(rhs, value, pos)) abort();
+    foreach (Bindings::iterator, i, *args[0]->attrs) {
+        string key = aterm2String(i->first);
         startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
 
         try {
@@ -321,15 +315,9 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
             /* The `args' attribute is special: it supplies the
                command-line arguments to the builder. */
             if (key == "args") {
-                ATermList es;
-                value = evalExpr(state, value);
-                if (!matchList(value, es)) {
-                    static bool haveWarned = false;
-                    warnOnce(haveWarned, "the `args' attribute should evaluate to a list");
-                    es = flattenList(state, value);
-                }
-                for (ATermIterator i(es); i; ++i) {
-                    string s = coerceToString(state, *i, context, true);
+                state.forceList(i->second);
+                for (unsigned int n = 0; n < i->second.list.length; ++n) {
+                    string s = state.coerceToString(i->second.list.elems[n], context, true);
                     drv.args.push_back(s);
                 }
             }
@@ -337,7 +325,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
             /* All other attributes are passed to the builder through
                the environment. */
             else {
-                string s = coerceToString(state, value, context, true);
+                string s = state.coerceToString(i->second, context, true);
                 drv.env[key] = s;
                 if (key == "builder") drv.builder = s;
                 else if (key == "system") drv.platform = s;
@@ -352,13 +340,12 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
             }
 
         } catch (Error & e) {
-            e.addPrefix(format("while evaluating the derivation attribute `%1%' at %2%:\n")
-                % key % showPos(pos));
-            e.addPrefix(format("while instantiating the derivation named `%1%' at %2%:\n")
-                % drvName % showPos(posDrvName));
+            e.addPrefix(format("while evaluating the derivation attribute `%1%' at <SOMEWHERE>:\n")
+                % key /* !!! % showPos(pos) */);
+            e.addPrefix(format("while instantiating the derivation named `%1%' at <SOMEWHERE>:\n")
+                % drvName /* !!! % showPos(posDrvName) */);
             throw;
         }
-
     }
     
     /* Everything in the context of the strings in the derivation
@@ -466,25 +453,25 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
     state.drvHashes[drvPath] = hashDerivationModulo(state, drv);
 
     /* !!! assumes a single output */
-    ATermMap outAttrs(2);
-    outAttrs.set(toATerm("outPath"),
-        makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos()));
-    outAttrs.set(toATerm("drvPath"),
-        makeAttrRHS(makeStr(drvPath, singleton<PathSet>("=" + drvPath)), makeNoPos()));
-
-    return makeAttrs(outAttrs);
+    //state.mkAttrs(v);
+    state.cloneAttrs(*args[0], v);
+    mkString((*v.attrs)[toATerm("outPath")], outPath, singleton<PathSet>(drvPath));
+    mkString((*v.attrs)[toATerm("drvPath")], drvPath, singleton<PathSet>("=" + drvPath));
+    mkString((*v.attrs)[toATerm("type")], "derivation"); // !!! remove
 }
 
 
 static void prim_derivationLazy(EvalState & state, Value * * args, Value & v)
 {
-    Expr eAttrs = evalExpr(state, args[0]);
-    ATermMap attrs;    
-    queryAllAttrs(eAttrs, attrs, true);
+    state.forceAttrs(*args[0]);
+
+    state.cloneAttrs(*args[0], v);
 
-    attrs.set(toATerm("type"),
-        makeAttrRHS(makeStr("derivation"), makeNoPos()));
+    mkString((*v.attrs)[toATerm("type")], "derivation");
 
+    /* !!! */
+
+#if 0    
     Expr drvStrict = makeCall(makeVar(toATerm("derivation!")), eAttrs);
 
     attrs.set(toATerm("outPath"),
@@ -493,8 +480,8 @@ static void prim_derivationLazy(EvalState & state, Value * * args, Value & v)
         makeAttrRHS(makeSelect(drvStrict, toATerm("drvPath")), makeNoPos()));
     
     return makeAttrs(attrs);
-}
 #endif
+}
 
 
 /*************************************************************
@@ -592,6 +579,7 @@ static void prim_toXML(EvalState & state, Value * * args, Value & v)
     printTermAsXML(strictEvalExpr(state, args[0]), out, context);
     return makeStr(out.str(), context);
 }
+#endif
 
 
 /* Store a string in the Nix store as a source file that can be used
@@ -599,12 +587,12 @@ static void prim_toXML(EvalState & state, Value * * args, Value & v)
 static void prim_toFile(EvalState & state, Value * * args, Value & v)
 {
     PathSet context;
-    string name = evalStringNoCtx(state, args[0]);
-    string contents = evalString(state, args[1], context);
+    string name = state.forceStringNoCtx(*args[0]);
+    string contents = state.forceString(*args[1]); // !!! context
 
     PathSet refs;
 
-    for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
+    foreach (PathSet::iterator, i, context) {
         Path path = *i;
         if (path.at(0) == '=') path = string(path, 1);
         if (isDerivation(path))
@@ -619,11 +607,12 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v)
     /* Note: we don't need to add `context' to the context of the
        result, since `storePath' itself has references to the paths
        used in args[1]. */
-    
-    return makeStr(storePath, singleton<PathSet>(storePath));
+
+    mkString(v, storePath, singleton<PathSet>(storePath));
 }
 
 
+#if 0
 struct FilterFromExpr : PathFilter
 {
     EvalState & state;
@@ -731,10 +720,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
     state.forceAttrs(*args[0]);
     state.forceList(*args[1]);
 
-    state.mkAttrs(v);
-        
-    foreach (Bindings::iterator, i, *args[0]->attrs)
-        (*v.attrs)[i->first] = i->second;
+    state.cloneAttrs(*args[0], v);
 
     for (unsigned int i = 0; i < args[1]->list.length; ++i) {
         state.forceStringNoCtx(args[1]->list.elems[i]);
@@ -743,40 +729,32 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
 }
 
 
-#if 0
 /* Builds an attribute set from a list specifying (name, value)
    pairs.  To be precise, a list [{name = "name1"; value = value1;}
    ... {name = "nameN"; value = valueN;}] is transformed to {name1 =
    value1; ... nameN = valueN;}. */
 static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
 {
-    try {
-        ATermMap res = ATermMap();
-        ATermList list;
-        list = evalList(state, args[0]);
-        for (ATermIterator i(list); i; ++i){
-            // *i should now contain a pointer to the list item expression
-            ATermList attrs;
-            Expr evaledExpr = evalExpr(state, *i);
-            if (matchAttrs(evaledExpr, attrs)){
-                Expr e = evalExpr(state, makeSelect(evaledExpr, toATerm("name")));
-                string attr = evalStringNoCtx(state,e);
-                Expr r = makeSelect(evaledExpr, toATerm("value"));
-                res.set(toATerm(attr), makeAttrRHS(r, makeNoPos()));
-            }
-            else
-                throw TypeError(format("list element in `listToAttrs' is %s, expected a set { name = \"<name>\"; value = <value>; }")
-                    % showType(evaledExpr));
-        }
-    
-        return makeAttrs(res);
-    
-    } catch (Error & e) {
-        e.addPrefix(format("in `listToAttrs':\n"));
-        throw;
+    state.forceList(*args[0]);
+
+    state.mkAttrs(v);
+
+    for (unsigned int i = 0; i < args[0]->list.length; ++i) {
+        Value & v2(args[0]->list.elems[i]);
+        state.forceAttrs(v2);
+        
+        Bindings::iterator j = v2.attrs->find(toATerm("name"));
+        if (j == v2.attrs->end())
+            throw TypeError("`name' attribute missing in a call to `listToAttrs'");
+        string name = state.forceStringNoCtx(j->second);
+        
+        j = v2.attrs->find(toATerm("value"));
+        if (j == v2.attrs->end())
+            throw TypeError("`value' attribute missing in a call to `listToAttrs'");
+
+        (*v.attrs)[toATerm(name)] = j->second; // !!! sharing?
     }
 }
-#endif
 
 
 #if 0
@@ -897,7 +875,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
 static void prim_length(EvalState & state, Value * * args, Value & v)
 {
     state.forceList(*args[0]);
-    mkInt(v, v.list.length);
+    mkInt(v, args[0]->list.length);
 }
 
 
@@ -1111,11 +1089,11 @@ void EvalState::createBaseEnv()
     // Expr <-> String
     addPrimOp("__exprToString", 1, prim_exprToString);
     addPrimOp("__stringToExpr", 1, prim_stringToExpr);
+#endif
 
     // Derivations
-    addPrimOp("derivation!", 1, prim_derivationStrict);
-    addPrimOp("derivation", 1, prim_derivationLazy);
-#endif
+    addPrimOp("derivation", 1, prim_derivationStrict);
+    //addPrimOp("derivation", 1, prim_derivationLazy);
 
     // Paths
     addPrimOp("__toPath", 1, prim_toPath);
@@ -1130,7 +1108,9 @@ void EvalState::createBaseEnv()
     // Creating files
 #if 0
     addPrimOp("__toXML", 1, prim_toXML);
+#endif
     addPrimOp("__toFile", 2, prim_toFile);
+#if 0
     addPrimOp("__filterSource", 2, prim_filterSource);
 #endif
 
@@ -1140,8 +1120,8 @@ void EvalState::createBaseEnv()
     addPrimOp("__hasAttr", 2, prim_hasAttr);
     addPrimOp("__isAttrs", 1, prim_isAttrs);
     addPrimOp("removeAttrs", 2, prim_removeAttrs);
-#if 0
     addPrimOp("__listToAttrs", 1, prim_listToAttrs);
+#if 0
     addPrimOp("__intersectAttrs", 2, prim_intersectAttrs);
     addPrimOp("__functionArgs", 1, prim_functionArgs);
 #endif
diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc
index 86bb1841b9a0..a71998de24d3 100644
--- a/src/nix-instantiate/nix-instantiate.cc
+++ b/src/nix-instantiate/nix-instantiate.cc
@@ -75,8 +75,23 @@ void processExpr(EvalState & state, const Strings & attrPaths,
         std::cout << format("%1%\n") % canonicaliseExpr(e);
     else {
         Value v;
-        state.strictEval(e, v);
-        std::cout << v << std::endl;
+        if (strict) state.strictEval(e, v); else state.eval(e, v);
+        if (evalOnly)
+            std::cout << v << std::endl;
+        else {
+            DrvInfos drvs;
+            getDerivations(state, v, "", autoArgs, drvs);
+            foreach (DrvInfos::iterator, i, drvs) {
+                Path drvPath = i->queryDrvPath(state);
+                if (gcRoot == "")
+                    printGCWarning();
+                else
+                    drvPath = addPermRoot(drvPath,
+                        makeRootName(gcRoot, rootNr),
+                        indirectRoot);
+                std::cout << format("%1%\n") % drvPath;
+            }
+        }
     }
     
 #if 0