* Make `import' work.
This commit is contained in:
parent
31428c3a06
commit
d78a05ab40
|
@ -13,7 +13,7 @@ using namespace nix;
|
||||||
void doTest(string s)
|
void doTest(string s)
|
||||||
{
|
{
|
||||||
EvalState state;
|
EvalState state;
|
||||||
Expr e = parseExprFromString(state, s, "/");
|
Expr e = parseExprFromString(state, s, absPath("."));
|
||||||
printMsg(lvlError, format(">>>>> %1%") % e);
|
printMsg(lvlError, format(">>>>> %1%") % e);
|
||||||
Value v;
|
Value v;
|
||||||
state.strictEval(e, v);
|
state.strictEval(e, v);
|
||||||
|
@ -66,6 +66,8 @@ void run(Strings args)
|
||||||
doTest("if false then 1 else 2");
|
doTest("if false then 1 else 2");
|
||||||
doTest("if false || true 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("let x = x; in if true || x then 1 else 2");
|
||||||
|
doTest("/etc/passwd");
|
||||||
|
doTest("import ./foo.nix");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ std::ostream & operator << (std::ostream & str, Value & v)
|
||||||
case tString:
|
case tString:
|
||||||
str << "\"" << v.string.s << "\""; // !!! escaping
|
str << "\"" << v.string.s << "\""; // !!! escaping
|
||||||
break;
|
break;
|
||||||
|
case tPath:
|
||||||
|
str << v.path; // !!! escaping?
|
||||||
|
break;
|
||||||
case tNull:
|
case tNull:
|
||||||
str << "true";
|
str << "true";
|
||||||
break;
|
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 */
|
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;
|
ATerm s; ATermList context;
|
||||||
if (matchStr(e, s, context)) {
|
if (matchStr(e, s, context)) {
|
||||||
assert(context == ATempty);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,8 +304,14 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
eval(env, e2, v);
|
eval(env, e2, v);
|
||||||
forceAttrs(v); // !!! eval followed by force is slightly inefficient
|
forceAttrs(v); // !!! eval followed by force is slightly inefficient
|
||||||
Bindings::iterator i = v.attrs->find(name);
|
Bindings::iterator i = v.attrs->find(name);
|
||||||
if (i == v.attrs->end()) throw TypeError("attribute not found");
|
if (i == v.attrs->end())
|
||||||
forceValue(i->second);
|
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;
|
v = i->second;
|
||||||
return;
|
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)
|
bool EvalState::eqValues(Value & v1, Value & v2)
|
||||||
{
|
{
|
||||||
forceValue(v1);
|
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))
|
LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos))
|
||||||
{
|
{
|
||||||
if (!evalBool(state, cond))
|
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);
|
static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct Value
|
||||||
const char * s;
|
const char * s;
|
||||||
const char * * context;
|
const char * * context;
|
||||||
} string;
|
} string;
|
||||||
|
const char * path;
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
struct {
|
struct {
|
||||||
unsigned int length;
|
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, PathSet> DrvRoots;
|
||||||
typedef std::map<Path, Hash> DrvHashes;
|
typedef std::map<Path, Hash> DrvHashes;
|
||||||
|
|
||||||
|
@ -134,6 +142,10 @@ struct EvalState
|
||||||
|
|
||||||
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
|
/* Evaluate an expression to normal form, storing the result in
|
||||||
value `v'. */
|
value `v'. */
|
||||||
void eval(Expr e, Value & v);
|
void eval(Expr e, Value & v);
|
||||||
|
@ -157,6 +169,18 @@ struct EvalState
|
||||||
void forceAttrs(Value & v);
|
void forceAttrs(Value & v);
|
||||||
void forceList(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:
|
private:
|
||||||
|
|
||||||
/* The base environment, containing the builtin functions and
|
/* The base environment, containing the builtin functions and
|
||||||
|
@ -182,9 +206,6 @@ private:
|
||||||
/* Evaluate an expression to normal form. */
|
/* Evaluate an expression to normal form. */
|
||||||
Expr evalExpr(EvalState & state, Expr e);
|
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
|
/* Evaluate an expression, and recursively evaluate list elements and
|
||||||
attributes. If `canonicalise' is true, we remove things like
|
attributes. If `canonicalise' is true, we remove things like
|
||||||
position information and make sure that attribute sets are in
|
position information and make sure that attribute sets are in
|
||||||
|
@ -202,17 +223,6 @@ ATermList evalList(EvalState & state, Expr e);
|
||||||
a list). */
|
a list). */
|
||||||
ATermList flattenList(EvalState & state, Expr e);
|
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
|
/* 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,
|
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(). */
|
not a normal form; it should be evaluated by calling evalExpr(). */
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
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)
|
static Expr prim_currentTime(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
return ATmake("Int(<int>)", time(0));
|
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
|
/* Load and evaluate an expression from path specified by the
|
||||||
argument. */
|
argument. */
|
||||||
static Expr prim_import(EvalState & state, const ATermVector & args)
|
static void prim_import(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
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) {
|
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
|
||||||
assert(isStorePath(*i));
|
assert(isStorePath(*i));
|
||||||
|
@ -106,10 +98,11 @@ static Expr prim_import(EvalState & state, const ATermVector & args)
|
||||||
store->buildDerivations(singleton<PathSet>(*i));
|
store->buildDerivations(singleton<PathSet>(*i));
|
||||||
}
|
}
|
||||||
|
|
||||||
return evalFile(state, path);
|
state.evalFile(path, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* Determine whether the argument is the null value. */
|
/* Determine whether the argument is the null value. */
|
||||||
static Expr prim_isNull(EvalState & state, const ATermVector & args)
|
static Expr prim_isNull(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
|
@ -1134,7 +1127,7 @@ void EvalState::createBaseEnv()
|
||||||
v.type = tNull;
|
v.type = tNull;
|
||||||
}
|
}
|
||||||
{ Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")];
|
{ Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")];
|
||||||
mkString(v, thisSystem.c_str()); // !!! copy string
|
mkString(v, strdup(thisSystem.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1143,7 +1136,9 @@ void EvalState::createBaseEnv()
|
||||||
addPrimOp("__currentTime", 0, prim_currentTime);
|
addPrimOp("__currentTime", 0, prim_currentTime);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
|
#endif
|
||||||
addPrimOp("import", 1, prim_import);
|
addPrimOp("import", 1, prim_import);
|
||||||
|
#if 0
|
||||||
addPrimOp("isNull", 1, prim_isNull);
|
addPrimOp("isNull", 1, prim_isNull);
|
||||||
addPrimOp("__isFunction", 1, prim_isFunction);
|
addPrimOp("__isFunction", 1, prim_isFunction);
|
||||||
addPrimOp("__isString", 1, prim_isString);
|
addPrimOp("__isString", 1, prim_isString);
|
||||||
|
|
Loading…
Reference in a new issue