about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval-test.cc4
-rw-r--r--src/libexpr/eval.cc138
-rw-r--r--src/libexpr/eval.hh38
-rw-r--r--src/libexpr/primops.cc23
4 files changed, 141 insertions, 62 deletions
diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc
index d37014a731..8aade1298f 100644
--- a/src/libexpr/eval-test.cc
+++ b/src/libexpr/eval-test.cc
@@ -13,7 +13,7 @@ using namespace nix;
 void doTest(string s)
 {
     EvalState state;
-    Expr e = parseExprFromString(state, s, "/");
+    Expr e = parseExprFromString(state, s, absPath("."));
     printMsg(lvlError, format(">>>>> %1%") % e);
     Value v;
     state.strictEval(e, v);
@@ -66,6 +66,8 @@ void run(Strings args)
     doTest("if false then 1 else 2");
     doTest("if false || true then 1 else 2");
     doTest("let x = x; in if true || x then 1 else 2");
+    doTest("/etc/passwd");
+    doTest("import ./foo.nix");
 }
 
 
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 794e396602..86484031b1 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -29,6 +29,9 @@ std::ostream & operator << (std::ostream & str, Value & v)
     case tString:
         str << "\"" << v.string.s << "\""; // !!! escaping
         break;
+    case tPath:
+        str << v.path; // !!! escaping?
+        break;
     case tNull:
         str << "true";
         break;
@@ -209,6 +212,20 @@ Env & EvalState::allocEnv()
 }
 
 
+void EvalState::evalFile(const Path & path, Value & v)
+{
+    startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
+    Expr e = parseExprFromFile(*this, path);
+    try {
+        eval(e, v);
+    } catch (Error & e) {
+        e.addPrefix(format("while evaluating the file `%1%':\n")
+            % path);
+        throw;
+    }
+}
+
+
 static char * deepestStack = (char *) -1; /* for measuring stack usage */
 
 
@@ -241,7 +258,12 @@ void EvalState::eval(Env & env, Expr e, Value & v)
     ATerm s; ATermList context;
     if (matchStr(e, s, context)) {
         assert(context == ATempty);
-        mkString(v, ATgetName(ATgetAFun(s)));
+        mkString(v, strdup(ATgetName(ATgetAFun(s))));
+        return;
+    }
+
+    if (matchPath(e, s)) {
+        mkPath(v, strdup(ATgetName(ATgetAFun(s))));
         return;
     }
 
@@ -282,8 +304,14 @@ void EvalState::eval(Env & env, Expr e, Value & v)
         eval(env, e2, v);
         forceAttrs(v); // !!! eval followed by force is slightly inefficient
         Bindings::iterator i = v.attrs->find(name);
-        if (i == v.attrs->end()) throw TypeError("attribute not found");
-        forceValue(i->second);
+        if (i == v.attrs->end())
+            throwEvalError("attribute `%1%' missing", aterm2String(name));
+        try {            
+            forceValue(i->second);
+        } catch (Error & e) {
+            addErrorPrefix(e, "while evaluating the attribute `%1%':\n", aterm2String(name));
+            throw;
+        }
         v = i->second;
         return;
     }
@@ -569,6 +597,80 @@ void EvalState::forceList(Value & v)
 }
 
 
+string EvalState::coerceToString(Value & v, PathSet & context,
+    bool coerceMore, bool copyToStore)
+{
+    forceValue(v);
+
+    string s;
+
+    if (v.type == tString) return v.string.s;
+
+    if (v.type == tPath) {
+        Path path(canonPath(v.path));
+
+        if (!copyToStore) return path;
+        
+        if (isDerivation(path))
+            throw EvalError(format("file names are not allowed to end in `%1%'")
+                % drvExtension);
+
+        Path dstPath;
+        if (srcToStore[path] != "")
+            dstPath = srcToStore[path];
+        else {
+            dstPath = readOnlyMode
+                ? computeStorePathForPath(path).first
+                : store->addToStore(path);
+            srcToStore[path] = dstPath;
+            printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
+                % path % dstPath);
+        }
+
+        context.insert(dstPath);
+        return dstPath;
+    }
+
+    if (v.type == tAttrs) {
+        Bindings::iterator i = v.attrs->find(toATerm("outPath"));
+        if (i == v.attrs->end())
+            throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
+        return coerceToString(i->second, context, coerceMore, copyToStore);
+    }
+
+    if (coerceMore) {
+
+        /* Note that `false' is represented as an empty string for
+           shell scripting convenience, just like `null'. */
+        if (v.type == tBool && v.boolean) return "1";
+        if (v.type == tBool && !v.boolean) return "";
+        if (v.type == tInt) return int2String(v.integer);
+        if (v.type == tNull) return "";
+
+        if (v.type == tList) {
+            string result;
+            for (unsigned int n = 0; n < v.list.length; ++n) {
+                if (n) result += " ";
+                result += coerceToString(v.list.elems[n],
+                    context, coerceMore, copyToStore);
+            }
+            return result;
+        }
+    }
+    
+    throwTypeError("cannot coerce %1% to a string", showType(v));
+}
+
+
+Path EvalState::coerceToPath(Value & v, PathSet & context)
+{
+    string path = coerceToString(v, context, false, false);
+    if (path == "" || path[0] != '/')
+        throw EvalError(format("string `%1%' doesn't represent an absolute path") % path);
+    return path;
+}
+
+
 bool EvalState::eqValues(Value & v1, Value & v2)
 {
     forceValue(v1);
@@ -1046,22 +1148,6 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
 }
 
 
-LocalNoInline(Expr evalSelect(EvalState & state, Expr e, ATerm name))
-{
-    ATerm pos;
-    string s = aterm2String(name);
-    Expr a = queryAttr(evalExpr(state, e), s, pos);
-    if (!a) throwEvalError("attribute `%1%' missing", s);
-    try {
-        return evalExpr(state, a);
-    } catch (Error & e) {
-        addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
-            s, showPos(pos));
-        throw;
-    }
-}
-
-
 LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos))
 {
     if (!evalBool(state, cond))
@@ -1352,20 +1438,6 @@ Expr evalExpr(EvalState & state, Expr e)
 }
 
 
-Expr evalFile(EvalState & state, const Path & path)
-{
-    startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
-    Expr e = parseExprFromFile(state, path);
-    try {
-        return evalExpr(state, e);
-    } catch (Error & e) {
-        e.addPrefix(format("while evaluating the file `%1%':\n")
-            % path);
-        throw;
-    }
-}
-
-
 static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs);
 
 
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 8ca997f140..4706602d59 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -58,6 +58,7 @@ struct Value
             const char * s;
             const char * * context;
         } string;
+        const char * path;
         Bindings * attrs;
         struct {
             unsigned int length;
@@ -107,6 +108,13 @@ static inline void mkString(Value & v, const char * s)
 }
 
 
+static inline void mkPath(Value & v, const char * s)
+{
+    v.type = tPath;
+    v.path = s;
+}
+
+
 typedef std::map<Path, PathSet> DrvRoots;
 typedef std::map<Path, Hash> DrvHashes;
 
@@ -134,6 +142,10 @@ struct EvalState
 
     EvalState();
 
+    /* Evaluate an expression read from the given file to normal
+       form. */
+    void evalFile(const Path & path, Value & v);
+
     /* Evaluate an expression to normal form, storing the result in
        value `v'. */
     void eval(Expr e, Value & v);
@@ -157,6 +169,18 @@ struct EvalState
     void forceAttrs(Value & v);
     void forceList(Value & v);
 
+    /* String coercion.  Converts strings, paths and derivations to a
+       string.  If `coerceMore' is set, also converts nulls, integers,
+       booleans and lists to a string.  If `copyToStore' is set,
+       referenced paths are copied to the Nix store as a side effect.q */
+    string coerceToString(Value & v, PathSet & context,
+        bool coerceMore = false, bool copyToStore = true);
+
+    /* Path coercion.  Converts strings, paths and derivations to a
+       path.  The result is guaranteed to be a canonicalised, absolute
+       path.  Nothing is copied to the store. */
+    Path coerceToPath(Value & v, PathSet & context);
+
 private:
 
     /* The base environment, containing the builtin functions and
@@ -182,9 +206,6 @@ private:
 /* Evaluate an expression to normal form. */
 Expr evalExpr(EvalState & state, Expr e);
 
-/* Evaluate an expression read from the given file to normal form. */
-Expr evalFile(EvalState & state, const Path & path);
-
 /* Evaluate an expression, and recursively evaluate list elements and
    attributes.  If `canonicalise' is true, we remove things like
    position information and make sure that attribute sets are in
@@ -202,17 +223,6 @@ ATermList evalList(EvalState & state, Expr e);
    a list). */
 ATermList flattenList(EvalState & state, Expr e);
 
-/* String coercion.  Converts strings, paths and derivations to a
-   string.  If `coerceMore' is set, also converts nulls, integers,
-   booleans and lists to a string. */
-string coerceToString(EvalState & state, Expr e, PathSet & context,
-    bool coerceMore = false, bool copyToStore = true);
-
-/* Path coercion.  Converts strings, paths and derivations to a path.
-   The result is guaranteed to be an canonicalised, absolute path.
-   Nothing is copied to the store. */
-Path coerceToPath(EvalState & state, Expr e, PathSet & context);
-
 /* Automatically call a function for which each argument has a default
    value or has a binding in the `args' map.  Note: result is a call,
    not a normal form; it should be evaluated by calling evalExpr(). */
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index a24f40be67..2815567e5d 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -14,6 +14,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <cstring>
 
 
 namespace nix {
@@ -69,20 +70,11 @@ static Expr prim_null(EvalState & state, const ATermVector & args)
 }
 
 
-/* Return a string constant representing the current platform.  Note!
-   that differs between platforms, so Nix expressions using
-   `__currentSystem' can evaluate to different values on different
-   platforms. */
-static Expr prim_currentSystem(EvalState & state, const ATermVector & args)
-{
-    return makeStr(thisSystem);
-}
-
-
 static Expr prim_currentTime(EvalState & state, const ATermVector & args)
 {
     return ATmake("Int(<int>)", time(0));
 }
+#endif
 
 
 /*************************************************************
@@ -92,10 +84,10 @@ static Expr prim_currentTime(EvalState & state, const ATermVector & args)
 
 /* Load and evaluate an expression from path specified by the
    argument. */ 
-static Expr prim_import(EvalState & state, const ATermVector & args)
+static void prim_import(EvalState & state, Value * * args, Value & v)
 {
     PathSet context;
-    Path path = coerceToPath(state, args[0], context);
+    Path path = state.coerceToPath(*args[0], context);
 
     for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
         assert(isStorePath(*i));
@@ -106,10 +98,11 @@ static Expr prim_import(EvalState & state, const ATermVector & args)
             store->buildDerivations(singleton<PathSet>(*i));
     }
 
-    return evalFile(state, path);
+    state.evalFile(path, v);
 }
 
 
+#if 0
 /* Determine whether the argument is the null value. */
 static Expr prim_isNull(EvalState & state, const ATermVector & args)
 {
@@ -1134,7 +1127,7 @@ void EvalState::createBaseEnv()
         v.type = tNull;
     }
     {   Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")];
-        mkString(v, thisSystem.c_str()); // !!! copy string
+        mkString(v, strdup(thisSystem.c_str()));
     }
 
 #if 0    
@@ -1143,7 +1136,9 @@ void EvalState::createBaseEnv()
     addPrimOp("__currentTime", 0, prim_currentTime);
 
     // Miscellaneous
+#endif
     addPrimOp("import", 1, prim_import);
+#if 0
     addPrimOp("isNull", 1, prim_isNull);
     addPrimOp("__isFunction", 1, prim_isFunction);
     addPrimOp("__isString", 1, prim_isString);