aboutsummaryrefslogtreecommitdiff
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 d37014a73..8aade1298 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 794e39660..86484031b 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 8ca997f14..4706602d5 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 a24f40be6..2815567e5 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);