about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-07-26T15·05+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-07-26T15·05+0000
commitca2238cf818e27ebb663c83a9fe9ae7f58eb830f (patch)
tree7d8b058e7139c69666ee045f30070fc2500fafe5 /src
parent2317d8f6712b2d4e249b8b1206f9e0a9c4269fc0 (diff)
* Refactoring: get the selection path stuff out of getDerivations()
  and put it into a separate function findAlongAttrPath().

Diffstat (limited to 'src')
-rw-r--r--src/libexpr/Makefile.am3
-rw-r--r--src/libexpr/attr-path.cc74
-rw-r--r--src/libexpr/attr-path.hh13
-rw-r--r--src/libexpr/eval.cc22
-rw-r--r--src/libexpr/eval.hh5
-rw-r--r--src/libexpr/get-drvs.cc131
-rw-r--r--src/libexpr/get-drvs.hh4
-rw-r--r--src/nix-env/main.cc12
-rw-r--r--src/nix-instantiate/main.cc25
9 files changed, 170 insertions, 119 deletions
diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am
index 1e77420d51..d59b798c0b 100644
--- a/src/libexpr/Makefile.am
+++ b/src/libexpr/Makefile.am
@@ -3,7 +3,8 @@ lib_LTLIBRARIES = libexpr.la
 libexpr_la_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \
  eval.cc eval.hh primops.cc \
  lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h \
- get-drvs.cc get-drvs.hh
+ get-drvs.cc get-drvs.hh \
+ attr-path.cc attr-path.hh
 
 BUILT_SOURCES = nixexpr-ast.cc nixexpr-ast.hh \
  parser-tab.h lexer-tab.h parser-tab.c lexer-tab.c
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
new file mode 100644
index 0000000000..274f49ceab
--- /dev/null
+++ b/src/libexpr/attr-path.cc
@@ -0,0 +1,74 @@
+#include "attr-path.hh"
+#include "nixexpr-ast.hh"
+
+
+bool isAttrs(EvalState & state, Expr e, ATermMap & attrs)
+{
+    e = evalExpr(state, e);
+    ATermList dummy;
+    if (!matchAttrs(e, dummy)) return false;
+    queryAllAttrs(e, attrs, false);
+    return true;
+}
+
+
+Expr findAlongAttrPath(EvalState & state, const string & attrPath, Expr e)
+{
+    Strings tokens = tokenizeString(attrPath, ".");
+
+    Error attrError =
+        Error(format("attribute selection path `%1%' does not match expression") % attrPath);
+
+    string curPath;
+    
+    for (Strings::iterator i = tokens.begin(); i != tokens.end(); ++i) {
+
+        if (!curPath.empty()) curPath += ".";
+        curPath += *i;
+
+        /* Is *i an index (integer) or a normal attribute name? */
+        enum { apAttr, apIndex } apType = apAttr;
+        string attr = *i;
+        int attrIndex = -1;
+        if (string2Int(attr, attrIndex)) apType = apIndex;
+
+        /* Evaluate the expression. */
+        e = evalExpr(state, autoCallFunction(evalExpr(state, e)));
+
+        /* It should evaluate to either an attribute set or an
+           expression, according to what is specified in the
+           attrPath. */
+
+        if (apType == apAttr) {
+
+            ATermMap attrs(128);
+
+            if (!isAttrs(state, e, attrs))
+                throw TypeError(
+                    format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
+                    % curPath % showType(e));
+                
+            e = attrs.get(toATerm(attr));
+            if (!e)
+                throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
+
+        }
+
+        else if (apType == apIndex) {
+
+            ATermList es;
+            if (!matchList(e, es))
+                throw TypeError(
+                    format("the expression selected by the selection path `%1%' should be a list but is %2%")
+                    % curPath % showType(e));
+
+            e = ATelementAt(es, attrIndex);
+            if (!e)
+                throw Error(format("list index %1% in selection path `%2%' not found") % attrIndex % curPath);
+            
+        }
+        
+    }
+    
+    return e;
+}
diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh
new file mode 100644
index 0000000000..f64ef7a7cd
--- /dev/null
+++ b/src/libexpr/attr-path.hh
@@ -0,0 +1,13 @@
+#ifndef __ATTR_PATH_H
+#define __ATTR_PATH_H
+
+#include <string>
+#include <map>
+
+#include "eval.hh"
+
+
+Expr findAlongAttrPath(EvalState & state, const string & attrPath, Expr e);
+
+
+#endif /* !__ATTR_PATH_H */
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index f1a600103d..6c78356db8 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -287,6 +287,24 @@ static ATerm concatStrings(EvalState & state, const ATermVector & args)
 }
 
 
+Expr autoCallFunction(Expr e)
+{
+    ATermList formals;
+    ATerm body, pos;
+    if (matchFunction(e, formals, body, pos)) {
+        for (ATermIterator i(formals); i; ++i) {
+            Expr name, def; ATerm values, def2;
+            if (!matchFormal(*i, name, values, def2)) abort();
+            if (!matchDefaultValue(def2, def))
+                throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1%')")
+                    % aterm2String(name));
+        }
+        e = makeCall(e, makeAttrs(ATermMap(0)));
+    }
+    return e;
+}
+
+
 Expr evalExpr2(EvalState & state, Expr e)
 {
     Expr e1, e2, e3, e4;
@@ -380,7 +398,9 @@ Expr evalExpr2(EvalState & state, Expr e)
             }
         }
         
-        else throw TypeError("the left-hand side of the function call is neither a function nor a primop (built-in operation)");
+        else throw TypeError(
+            format("the left-hand side of the function call is neither a function nor a primop (built-in operation) but %1%")
+            % showType(e1));
     }
 
     /* Attribute selection. */
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index a3815733e0..018c6b726b 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -59,6 +59,11 @@ string coerceToStringWithContext(EvalState & state,
     ATermList & context, Expr e, bool & isPath);
 Expr wrapInContext(ATermList context, Expr e);
 
+/* Automatically call a function for which each argument has a default
+   value.  Note: result is a call, not a normal form; it should be
+   evaluated by calling evalExpr(). */
+Expr autoCallFunction(Expr e);
+
 /* Print statistics. */
 void printEvalStats(EvalState & state);
 
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 736c3e522f..0afc7bd6d1 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -58,7 +58,7 @@ typedef set<Expr> Exprs;
    it makes sense for the caller to recursively search for derivations
    in `e'. */
 static bool getDerivation(EvalState & state, Expr e,
-    DrvInfos & drvs, Exprs & doneExprs, string attributeName)
+    const string & attrPath, DrvInfos & drvs, Exprs & doneExprs)
 {
     try {
         
@@ -92,7 +92,7 @@ static bool getDerivation(EvalState & state, Expr e,
 
         drv.attrs = attrs;
 
-        drv.attrPath = attributeName;
+        drv.attrPath = attrPath;
 
         drvs.push_back(drv);
         return false;
@@ -107,7 +107,7 @@ bool getDerivation(EvalState & state, Expr e, DrvInfo & drv)
 {
     Exprs doneExprs;
     DrvInfos drvs;
-    getDerivation(state, e, drvs, doneExprs, "");
+    getDerivation(state, e, "", drvs, doneExprs);
     if (drvs.size() != 1) return false;
     drv = drvs.front();
     return true;
@@ -121,118 +121,53 @@ static string addToPath(const string & s1, const string & s2)
 
 
 static void getDerivations(EvalState & state, Expr e,
-    DrvInfos & drvs, Exprs & doneExprs, const string & attrPath,
-    const string & pathTaken)
+    const string & pathPrefix, DrvInfos & drvs, Exprs & doneExprs)
 {
-    /* Automatically call functions for which each argument has a
-       default value. */
-    ATermList formals;
-    ATerm body, pos;
-    if (matchFunction(e, formals, body, pos)) {
-        for (ATermIterator i(formals); i; ++i) {
-            Expr name, def; ATerm values, def2;
-            if (!matchFormal(*i, name, values, def2)) abort();
-            if (!matchDefaultValue(def2, def))
-                throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1%')")
-                    % aterm2String(name));
-        }
-        getDerivations(state,
-            makeCall(e, makeAttrs(ATermMap(0))),
-            drvs, doneExprs, attrPath, pathTaken);
-        return;
-    }
-
-    /* Parse the start of attrPath. */
-    enum { apNone, apAttr, apIndex } apType;
-    string attrPathRest;
-    string attr;
-    int attrIndex;
-    Error attrError =
-        Error(format("attribute selection path `%1%' does not match expression") % attrPath);
-
-    if (attrPath.empty())
-        apType = apNone;
-    else {
-        string::size_type dot = attrPath.find(".");
-        if (dot == string::npos) {
-            attrPathRest = "";
-            attr = attrPath;
-        } else {
-            attrPathRest = string(attrPath, dot + 1);
-            attr = string(attrPath, 0, dot);
-        }
-        apType = apAttr;
-        if (string2Int(attr, attrIndex)) apType = apIndex;
-    }
+    e = evalExpr(state, autoCallFunction(evalExpr(state, e)));
 
     /* Process the expression. */
     ATermList es;
     DrvInfo drv;
 
-    if (!getDerivation(state, e, drvs, doneExprs, pathTaken)) {
-        if (apType != apNone) throw attrError;
+    if (!getDerivation(state, e, pathPrefix, drvs, doneExprs))
         return;
-    }
-
-    e = evalExpr(state, e);
 
     if (matchAttrs(e, es)) {
-        if (apType != apNone && apType != apAttr) throw attrError;
         ATermMap drvMap(ATgetLength(es));
         queryAllAttrs(e, drvMap);
-        if (apType == apNone) {
-            for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) {
-                startNest(nest, lvlDebug,
-                    format("evaluating attribute `%1%'") % aterm2String(i->key));
-                string pathTaken2 = addToPath(pathTaken, aterm2String(i->key));
-                if (getDerivation(state, i->value, drvs, doneExprs, pathTaken2)) {
-                    /* 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->value);
-                    if (matchAttrs(e, es)) {
-                        ATermMap attrs(ATgetLength(es));
-                        queryAllAttrs(e, attrs, false);
-                        Expr e2 = attrs.get(toATerm("recurseForDerivations"));
-                        if (e2 && evalBool(state, e2))
-                            getDerivations(state, e, drvs, doneExprs, attrPathRest, pathTaken2);
-                    }
+        
+        for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) {
+            startNest(nest, lvlDebug,
+                format("evaluating attribute `%1%'") % aterm2String(i->key));
+            string pathPrefix2 = addToPath(pathPrefix, aterm2String(i->key));
+            if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
+                /* 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->value);
+                if (matchAttrs(e, es)) {
+                    ATermMap attrs(ATgetLength(es));
+                    queryAllAttrs(e, attrs, false);
+                    Expr e2 = attrs.get(toATerm("recurseForDerivations"));
+                    if (e2 && evalBool(state, e2))
+                        getDerivations(state, e, pathPrefix2, drvs, doneExprs);
                 }
             }
-        } else {
-            Expr e2 = drvMap.get(toATerm(attr));
-            if (!e2) throw Error(format("attribute `%1%' in selection path not found") % attr);
-            startNest(nest, lvlDebug,
-                format("evaluating attribute `%1%'") % attr);
-            string pathTaken2 = addToPath(pathTaken, attr);
-            getDerivation(state, e2, drvs, doneExprs, pathTaken2);
-            if (!attrPath.empty())
-                getDerivations(state, e2, drvs, doneExprs, attrPathRest, pathTaken2);
         }
+        
         return;
     }
 
     if (matchList(e, es)) {
-        if (apType != apNone && apType != apIndex) throw attrError;
-        if (apType == apNone) {
-            int n = 0;
-            for (ATermIterator i(es); i; ++i, ++n) {
-                startNest(nest, lvlDebug,
-                    format("evaluating list element"));
-                string pathTaken2 = addToPath(pathTaken, (format("%1%") % n).str());
-                if (getDerivation(state, *i, drvs, doneExprs, pathTaken2))
-                    getDerivations(state, *i, drvs, doneExprs, attrPathRest, pathTaken2);
-            }
-        } else {
-            Expr e2 = ATelementAt(es, attrIndex);
-            if (!e2) throw Error(format("list index %1% in selection path not found") % attrIndex);
+        int n = 0;
+        for (ATermIterator i(es); i; ++i, ++n) {
             startNest(nest, lvlDebug,
                 format("evaluating list element"));
-            string pathTaken2 = addToPath(pathTaken, (format("%1%") % attrIndex).str());
-            if (getDerivation(state, e2, drvs, doneExprs, pathTaken2))
-                getDerivations(state, e2, drvs, doneExprs, attrPathRest, pathTaken2);
+            string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
+            if (getDerivation(state, *i, pathPrefix2, drvs, doneExprs))
+                getDerivations(state, *i, pathPrefix2, drvs, doneExprs);
         }
         return;
     }
@@ -241,9 +176,9 @@ static void getDerivations(EvalState & state, Expr e,
 }
 
 
-void getDerivations(EvalState & state, Expr e, DrvInfos & drvs,
-    const string & attrPath)
+void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
+    DrvInfos & drvs)
 {
     Exprs doneExprs;
-    getDerivations(state, e, drvs, doneExprs, attrPath, "");
+    getDerivations(state, e, pathPrefix, drvs, doneExprs);
 }
diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh
index 4fb8f43fee..84ffe25cab 100644
--- a/src/libexpr/get-drvs.hh
+++ b/src/libexpr/get-drvs.hh
@@ -49,8 +49,8 @@ typedef list<DrvInfo> DrvInfos;
    Otherwise, return false. */
 bool getDerivation(EvalState & state, Expr e, DrvInfo & drv);
 
-void getDerivations(EvalState & state, Expr e, DrvInfos & drvs,
-    const string & attrPath = "");
+void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
+    DrvInfos & drvs);
 
 
 #endif /* !__GET_DRVS_H */
diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc
index 875cdd7447..3fcaaff424 100644
--- a/src/nix-env/main.cc
+++ b/src/nix-env/main.cc
@@ -10,6 +10,7 @@
 #include "help.txt.hh"
 #include "nixexpr-ast.hh"
 #include "get-drvs.hh"
+#include "attr-path.hh"
 #include "pathlocks.hh"
 
 #include <cerrno>
@@ -36,7 +37,6 @@ struct InstallSourceInfo
     Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
     Path profile; /* for srcProfile */
     string systemFilter; /* for srcNixExprDrvs */
-    string attrPath; /* srcAttrPath */
 };
 
 
@@ -65,7 +65,7 @@ static void loadDerivations(EvalState & state, Path nixExprPath,
     string systemFilter, DrvInfos & elems)
 {
     getDerivations(state,
-        parseExprFromFile(state, absPath(nixExprPath)), elems);
+        parseExprFromFile(state, absPath(nixExprPath)), "", elems);
 
     /* Filter out all derivations not applicable to the current
        system. */
@@ -119,7 +119,7 @@ static DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
     e = bottomupRewrite(addPos, e);
 
     DrvInfos elems;
-    getDerivations(state, e, elems);
+    getDerivations(state, e, "", elems);
     return elems;
 }
 
@@ -334,7 +334,7 @@ static void queryInstSources(EvalState & state,
             {
                 Expr e2 = parseExprFromString(state, *i, absPath("."));
                 Expr call = makeCall(e2, e1);
-                getDerivations(state, call, elems);
+                getDerivations(state, call, "", elems);
             }
             
             break;
@@ -388,7 +388,9 @@ static void queryInstSources(EvalState & state,
             for (Strings::const_iterator i = args.begin();
                  i != args.end(); ++i)
                 getDerivations(state,
-                    parseExprFromFile(state, instSource.nixExprPath), elems, *i);
+                    findAlongAttrPath(state, *i, 
+                        parseExprFromFile(state, instSource.nixExprPath)),
+                    "", elems);
             break;
         }
     }
diff --git a/src/nix-instantiate/main.cc b/src/nix-instantiate/main.cc
index 31d61f3afe..963e81bac4 100644
--- a/src/nix-instantiate/main.cc
+++ b/src/nix-instantiate/main.cc
@@ -9,6 +9,7 @@
 #include "parser.hh"
 #include "nixexpr-ast.hh"
 #include "get-drvs.hh"
+#include "attr-path.hh"
 #include "help.txt.hh"
 
 
@@ -18,13 +19,12 @@ void printHelp()
 }
 
 
-static Expr evalStdin(EvalState & state, bool parseOnly)
+static Expr parseStdin(EvalState & state)
 {
-    startNest(nest, lvlTalkative, format("evaluating standard input"));
+    startNest(nest, lvlTalkative, format("parsing standard input"));
     string s, s2;
     while (getline(cin, s2)) s += s2 + "\n";
-    Expr e = parseExprFromString(state, s, absPath("."));
-    return parseOnly ? e : evalExpr(state, e);
+    return parseExprFromString(state, s, absPath("."));
 }
 
 
@@ -34,7 +34,7 @@ static bool indirectRoot = false;
 
 
 static void printResult(EvalState & state, Expr e,
-    bool evalOnly, bool printArgs, const string & attrPath)
+    bool evalOnly, bool printArgs)
 {
     if (evalOnly)
         cout << format("%1%\n") % e;
@@ -54,7 +54,7 @@ static void printResult(EvalState & state, Expr e,
     
     else {
         DrvInfos drvs;
-        getDerivations(state, e, drvs, attrPath);
+        getDerivations(state, e, "", drvs);
         for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i) {
             Path drvPath = i->queryDrvPath(state);
             if (gcRoot == "")
@@ -119,18 +119,19 @@ void run(Strings args)
     openDB();
 
     if (readStdin) {
-        Expr e = evalStdin(state, parseOnly);
-        printResult(state, e, evalOnly, printArgs, attrPath);
+        Expr e = findAlongAttrPath(state, attrPath, parseStdin(state));
+        if (!parseOnly) e = evalExpr(state, e);
+        printResult(state, e, evalOnly, printArgs);
     }
 
     for (Strings::iterator i = files.begin();
          i != files.end(); i++)
     {
         Path path = absPath(*i);
-        Expr e = parseOnly
-            ? parseExprFromFile(state, path)
-            : evalFile(state, path);
-        printResult(state, e, evalOnly, printArgs, attrPath);
+        Expr e = findAlongAttrPath(state, attrPath,
+            parseExprFromFile(state, path));
+        if (!parseOnly) e = evalExpr(state, e);
+        printResult(state, e, evalOnly, printArgs);
     }
 
     printEvalStats(state);