forked from lix-project/lix
* Organise primops.cc a bit better.
This commit is contained in:
parent
7349bd0176
commit
18e6096105
1 changed files with 429 additions and 374 deletions
|
@ -17,6 +17,11 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Constants
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
static Expr primBuiltins(EvalState & state, const ATermVector & args)
|
static Expr primBuiltins(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
/* Return an attribute set containing all primops. This allows
|
/* Return an attribute set containing all primops. This allows
|
||||||
|
@ -41,6 +46,47 @@ static Expr primBuiltins(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Boolean constructors. */
|
||||||
|
static Expr primTrue(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
return eTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primFalse(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
return eFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the null value. */
|
||||||
|
static Expr primNull(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
return makeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 primCurrentSystem(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
return makeStr(thisSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primCurrentTime(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
return ATmake("Int(<int>)", time(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Miscellaneous
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/* Load and evaluate an expression from path specified by the
|
/* Load and evaluate an expression from path specified by the
|
||||||
argument. */
|
argument. */
|
||||||
static Expr primImport(EvalState & state, const ATermVector & args)
|
static Expr primImport(EvalState & state, const ATermVector & args)
|
||||||
|
@ -61,16 +107,201 @@ static Expr primImport(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr primPathExists(EvalState & state, const ATermVector & args)
|
/* Convert the argument to a string. Paths are *not* copied to the
|
||||||
|
store, so `toString /foo/bar' yields `"/foo/bar"', not
|
||||||
|
`"/nix/store/whatever..."'. */
|
||||||
|
static Expr primToString(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
Path path = coerceToPath(state, args[0], context);
|
string s = coerceToString(state, args[0], context, true, false);
|
||||||
if (!context.empty())
|
return makeStr(s, context);
|
||||||
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
|
||||||
return makeBool(pathExists(path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Determine whether the argument is the null value. */
|
||||||
|
static Expr primIsNull(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
return makeBool(matchNull(evalExpr(state, args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Path findDependency(Path dir, string dep)
|
||||||
|
{
|
||||||
|
if (dep[0] == '/') throw EvalError(
|
||||||
|
format("illegal absolute dependency `%1%'") % dep);
|
||||||
|
|
||||||
|
Path p = canonPath(dir + "/" + dep);
|
||||||
|
|
||||||
|
if (pathExists(p))
|
||||||
|
return p;
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Make path `p' relative to directory `pivot'. E.g.,
|
||||||
|
relativise("/a/b/c", "a/b/x/y") => "../x/y". Both input paths
|
||||||
|
should be in absolute canonical form. */
|
||||||
|
static string relativise(Path pivot, Path p)
|
||||||
|
{
|
||||||
|
assert(pivot.size() > 0 && pivot[0] == '/');
|
||||||
|
assert(p.size() > 0 && p[0] == '/');
|
||||||
|
|
||||||
|
if (pivot == p) return ".";
|
||||||
|
|
||||||
|
/* `p' is in `pivot'? */
|
||||||
|
Path pivot2 = pivot + "/";
|
||||||
|
if (p.substr(0, pivot2.size()) == pivot2) {
|
||||||
|
return p.substr(pivot2.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, `p' is in a parent of `pivot'. Find up till which
|
||||||
|
path component `p' and `pivot' match, and add an appropriate
|
||||||
|
number of `..' components. */
|
||||||
|
string::size_type i = 1;
|
||||||
|
while (1) {
|
||||||
|
string::size_type j = pivot.find('/', i);
|
||||||
|
if (j == string::npos) break;
|
||||||
|
j++;
|
||||||
|
if (pivot.substr(0, j) != p.substr(0, j)) break;
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
string prefix;
|
||||||
|
unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
|
||||||
|
while (slashes--) {
|
||||||
|
prefix += "../";
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix + p.substr(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primDependencyClosure(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
startNest(nest, lvlDebug, "finding dependencies");
|
||||||
|
|
||||||
|
Expr attrs = evalExpr(state, args[0]);
|
||||||
|
|
||||||
|
/* Get the start set. */
|
||||||
|
Expr startSet = queryAttr(attrs, "startSet");
|
||||||
|
if (!startSet) throw EvalError("attribute `startSet' required");
|
||||||
|
ATermList startSet2 = evalList(state, startSet);
|
||||||
|
|
||||||
|
Path pivot;
|
||||||
|
PathSet workSet;
|
||||||
|
for (ATermIterator i(startSet2); i; ++i) {
|
||||||
|
PathSet context; /* !!! what to do? */
|
||||||
|
Path p = coerceToPath(state, *i, context);
|
||||||
|
workSet.insert(p);
|
||||||
|
pivot = dirOf(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the search path. */
|
||||||
|
PathSet searchPath;
|
||||||
|
Expr e = queryAttr(attrs, "searchPath");
|
||||||
|
if (e) {
|
||||||
|
ATermList list = evalList(state, e);
|
||||||
|
for (ATermIterator i(list); i; ++i) {
|
||||||
|
PathSet context; /* !!! what to do? */
|
||||||
|
Path p = coerceToPath(state, *i, context);
|
||||||
|
searchPath.insert(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr scanner = queryAttr(attrs, "scanner");
|
||||||
|
if (!scanner) throw EvalError("attribute `scanner' required");
|
||||||
|
|
||||||
|
/* Construct the dependency closure by querying the dependency of
|
||||||
|
each path in `workSet', adding the dependencies to
|
||||||
|
`workSet'. */
|
||||||
|
PathSet doneSet;
|
||||||
|
while (!workSet.empty()) {
|
||||||
|
Path path = *(workSet.begin());
|
||||||
|
workSet.erase(path);
|
||||||
|
|
||||||
|
if (doneSet.find(path) != doneSet.end()) continue;
|
||||||
|
doneSet.insert(path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
/* Call the `scanner' function with `path' as argument. */
|
||||||
|
debug(format("finding dependencies in `%1%'") % path);
|
||||||
|
ATermList deps = evalList(state, makeCall(scanner, makeStr(path)));
|
||||||
|
|
||||||
|
/* Try to find the dependencies relative to the `path'. */
|
||||||
|
for (ATermIterator i(deps); i; ++i) {
|
||||||
|
string s = evalStringNoCtx(state, *i);
|
||||||
|
|
||||||
|
Path dep = findDependency(dirOf(path), s);
|
||||||
|
|
||||||
|
if (dep == "") {
|
||||||
|
for (PathSet::iterator j = searchPath.begin();
|
||||||
|
j != searchPath.end(); ++j)
|
||||||
|
{
|
||||||
|
dep = findDependency(*j, s);
|
||||||
|
if (dep != "") break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dep == "")
|
||||||
|
debug(format("did NOT find dependency `%1%'") % s);
|
||||||
|
else {
|
||||||
|
debug(format("found dependency `%1%'") % dep);
|
||||||
|
workSet.insert(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addPrefix(format("while finding dependencies in `%1%':\n")
|
||||||
|
% path);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a list of the dependencies we've just found. */
|
||||||
|
ATermList deps = ATempty;
|
||||||
|
for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) {
|
||||||
|
deps = ATinsert(deps, makeStr(relativise(pivot, *i)));
|
||||||
|
deps = ATinsert(deps, makeStr(*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(format("dependency list is `%1%'") % makeList(deps));
|
||||||
|
|
||||||
|
return makeList(deps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primAbort(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
PathSet context;
|
||||||
|
throw Abort(format("evaluation aborted with the following error message: `%1%'") %
|
||||||
|
evalString(state, args[0], context));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return an environment variable. Use with care. */
|
||||||
|
static Expr primGetEnv(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
string name = evalStringNoCtx(state, args[0]);
|
||||||
|
return makeStr(getEnv(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primRelativise(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
PathSet context; /* !!! what to do? */
|
||||||
|
Path pivot = coerceToPath(state, args[0], context);
|
||||||
|
Path path = coerceToPath(state, args[1], context);
|
||||||
|
return makeStr(relativise(pivot, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Derivations
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/* Returns the hash of a derivation modulo fixed-output
|
/* Returns the hash of a derivation modulo fixed-output
|
||||||
subderivations. A fixed-output derivation is a derivation with one
|
subderivations. A fixed-output derivation is a derivation with one
|
||||||
output (`out') for which an expected hash and hash algorithm are
|
output (`out') for which an expected hash and hash algorithm are
|
||||||
|
@ -324,6 +555,30 @@ static Expr primDerivationLazy(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Paths
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert the argument to a path. !!! obsolete? */
|
||||||
|
static Expr primToPath(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
PathSet context;
|
||||||
|
string path = coerceToPath(state, args[0], context);
|
||||||
|
return makeStr(canonPath(path), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primPathExists(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
PathSet context;
|
||||||
|
Path path = coerceToPath(state, args[0], context);
|
||||||
|
if (!context.empty())
|
||||||
|
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
||||||
|
return makeBool(pathExists(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the base name of the given string, i.e., everything
|
/* Return the base name of the given string, i.e., everything
|
||||||
following the last slash. */
|
following the last slash. */
|
||||||
static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
|
static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
|
||||||
|
@ -346,24 +601,9 @@ static Expr primDirOf(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Convert the argument to a string. Paths are *not* copied to the
|
/*************************************************************
|
||||||
store, so `toString /foo/bar' yields `"/foo/bar"', not
|
* Creating files
|
||||||
`"/nix/store/whatever..."'. */
|
*************************************************************/
|
||||||
static Expr primToString(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
PathSet context;
|
|
||||||
string s = coerceToString(state, args[0], context, true, false);
|
|
||||||
return makeStr(s, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Convert the argument to a path. !!! obsolete? */
|
|
||||||
static Expr primToPath(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
PathSet context;
|
|
||||||
string path = coerceToPath(state, args[0], context);
|
|
||||||
return makeStr(canonPath(path), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Convert the argument (which can be any Nix expression) to an XML
|
/* Convert the argument (which can be any Nix expression) to an XML
|
||||||
|
@ -406,339 +646,6 @@ static Expr primToFile(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Boolean constructors. */
|
|
||||||
static Expr primTrue(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
return eTrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primFalse(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
return eFalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the null value. */
|
|
||||||
static Expr primNull(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
return makeNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Determine whether the argument is the null value. */
|
|
||||||
static Expr primIsNull(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
return makeBool(matchNull(evalExpr(state, args[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Determine whether the argument is a list. */
|
|
||||||
static Expr primIsList(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
ATermList list;
|
|
||||||
return makeBool(matchList(evalExpr(state, args[0]), list));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Path findDependency(Path dir, string dep)
|
|
||||||
{
|
|
||||||
if (dep[0] == '/') throw EvalError(
|
|
||||||
format("illegal absolute dependency `%1%'") % dep);
|
|
||||||
|
|
||||||
Path p = canonPath(dir + "/" + dep);
|
|
||||||
|
|
||||||
if (pathExists(p))
|
|
||||||
return p;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Make path `p' relative to directory `pivot'. E.g.,
|
|
||||||
relativise("/a/b/c", "a/b/x/y") => "../x/y". Both input paths
|
|
||||||
should be in absolute canonical form. */
|
|
||||||
static string relativise(Path pivot, Path p)
|
|
||||||
{
|
|
||||||
assert(pivot.size() > 0 && pivot[0] == '/');
|
|
||||||
assert(p.size() > 0 && p[0] == '/');
|
|
||||||
|
|
||||||
if (pivot == p) return ".";
|
|
||||||
|
|
||||||
/* `p' is in `pivot'? */
|
|
||||||
Path pivot2 = pivot + "/";
|
|
||||||
if (p.substr(0, pivot2.size()) == pivot2) {
|
|
||||||
return p.substr(pivot2.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, `p' is in a parent of `pivot'. Find up till which
|
|
||||||
path component `p' and `pivot' match, and add an appropriate
|
|
||||||
number of `..' components. */
|
|
||||||
string::size_type i = 1;
|
|
||||||
while (1) {
|
|
||||||
string::size_type j = pivot.find('/', i);
|
|
||||||
if (j == string::npos) break;
|
|
||||||
j++;
|
|
||||||
if (pivot.substr(0, j) != p.substr(0, j)) break;
|
|
||||||
i = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
string prefix;
|
|
||||||
unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
|
|
||||||
while (slashes--) {
|
|
||||||
prefix += "../";
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix + p.substr(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primDependencyClosure(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
startNest(nest, lvlDebug, "finding dependencies");
|
|
||||||
|
|
||||||
Expr attrs = evalExpr(state, args[0]);
|
|
||||||
|
|
||||||
/* Get the start set. */
|
|
||||||
Expr startSet = queryAttr(attrs, "startSet");
|
|
||||||
if (!startSet) throw EvalError("attribute `startSet' required");
|
|
||||||
ATermList startSet2 = evalList(state, startSet);
|
|
||||||
|
|
||||||
Path pivot;
|
|
||||||
PathSet workSet;
|
|
||||||
for (ATermIterator i(startSet2); i; ++i) {
|
|
||||||
PathSet context; /* !!! what to do? */
|
|
||||||
Path p = coerceToPath(state, *i, context);
|
|
||||||
workSet.insert(p);
|
|
||||||
pivot = dirOf(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the search path. */
|
|
||||||
PathSet searchPath;
|
|
||||||
Expr e = queryAttr(attrs, "searchPath");
|
|
||||||
if (e) {
|
|
||||||
ATermList list = evalList(state, e);
|
|
||||||
for (ATermIterator i(list); i; ++i) {
|
|
||||||
PathSet context; /* !!! what to do? */
|
|
||||||
Path p = coerceToPath(state, *i, context);
|
|
||||||
searchPath.insert(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr scanner = queryAttr(attrs, "scanner");
|
|
||||||
if (!scanner) throw EvalError("attribute `scanner' required");
|
|
||||||
|
|
||||||
/* Construct the dependency closure by querying the dependency of
|
|
||||||
each path in `workSet', adding the dependencies to
|
|
||||||
`workSet'. */
|
|
||||||
PathSet doneSet;
|
|
||||||
while (!workSet.empty()) {
|
|
||||||
Path path = *(workSet.begin());
|
|
||||||
workSet.erase(path);
|
|
||||||
|
|
||||||
if (doneSet.find(path) != doneSet.end()) continue;
|
|
||||||
doneSet.insert(path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
/* Call the `scanner' function with `path' as argument. */
|
|
||||||
debug(format("finding dependencies in `%1%'") % path);
|
|
||||||
ATermList deps = evalList(state, makeCall(scanner, makeStr(path)));
|
|
||||||
|
|
||||||
/* Try to find the dependencies relative to the `path'. */
|
|
||||||
for (ATermIterator i(deps); i; ++i) {
|
|
||||||
string s = evalStringNoCtx(state, *i);
|
|
||||||
|
|
||||||
Path dep = findDependency(dirOf(path), s);
|
|
||||||
|
|
||||||
if (dep == "") {
|
|
||||||
for (PathSet::iterator j = searchPath.begin();
|
|
||||||
j != searchPath.end(); ++j)
|
|
||||||
{
|
|
||||||
dep = findDependency(*j, s);
|
|
||||||
if (dep != "") break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dep == "")
|
|
||||||
debug(format("did NOT find dependency `%1%'") % s);
|
|
||||||
else {
|
|
||||||
debug(format("found dependency `%1%'") % dep);
|
|
||||||
workSet.insert(dep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Error & e) {
|
|
||||||
e.addPrefix(format("while finding dependencies in `%1%':\n")
|
|
||||||
% path);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a list of the dependencies we've just found. */
|
|
||||||
ATermList deps = ATempty;
|
|
||||||
for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) {
|
|
||||||
deps = ATinsert(deps, makeStr(relativise(pivot, *i)));
|
|
||||||
deps = ATinsert(deps, makeStr(*i));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(format("dependency list is `%1%'") % makeList(deps));
|
|
||||||
|
|
||||||
return makeList(deps);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primAbort(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
PathSet context;
|
|
||||||
throw Abort(format("evaluation aborted with the following error message: `%1%'") %
|
|
||||||
evalString(state, args[0], context));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the first element of a list. */
|
|
||||||
static Expr primHead(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
ATermList list = evalList(state, args[0]);
|
|
||||||
if (ATisEmpty(list))
|
|
||||||
throw Error("`head' called on an empty list");
|
|
||||||
return evalExpr(state, ATgetFirst(list));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return a list consisting of everything but the the first element of
|
|
||||||
a list. */
|
|
||||||
static Expr primTail(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
ATermList list = evalList(state, args[0]);
|
|
||||||
if (ATisEmpty(list))
|
|
||||||
throw Error("`tail' called on an empty list");
|
|
||||||
return makeList(ATgetNext(list));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return an environment variable. Use with care. */
|
|
||||||
static Expr primGetEnv(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
string name = evalStringNoCtx(state, args[0]);
|
|
||||||
return makeStr(getEnv(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the names of the attributes in an attribute set as a sorted
|
|
||||||
list of strings. */
|
|
||||||
static Expr primAttrNames(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
ATermMap attrs;
|
|
||||||
queryAllAttrs(evalExpr(state, args[0]), attrs);
|
|
||||||
|
|
||||||
StringSet names;
|
|
||||||
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
|
|
||||||
names.insert(aterm2String(i->key));
|
|
||||||
|
|
||||||
ATermList list = ATempty;
|
|
||||||
for (StringSet::const_reverse_iterator i = names.rbegin();
|
|
||||||
i != names.rend(); ++i)
|
|
||||||
list = ATinsert(list, makeStr(*i, PathSet()));
|
|
||||||
|
|
||||||
return makeList(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Apply a function to every element of a list. */
|
|
||||||
static Expr primMap(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
Expr fun = evalExpr(state, args[0]);
|
|
||||||
ATermList list = evalList(state, args[1]);
|
|
||||||
|
|
||||||
ATermList res = ATempty;
|
|
||||||
for (ATermIterator i(list); i; ++i)
|
|
||||||
res = ATinsert(res, makeCall(fun, *i));
|
|
||||||
|
|
||||||
return makeList(ATreverse(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 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 primCurrentSystem(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
return makeStr(thisSystem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primCurrentTime(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
return ATmake("Int(<int>)", time(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic version of the `.' operator. */
|
|
||||||
static Expr primGetAttr(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
string attr = evalStringNoCtx(state, args[0]);
|
|
||||||
return evalExpr(state, makeSelect(args[1], toATerm(attr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic version of the `?' operator. */
|
|
||||||
static Expr primHasAttr(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
string attr = evalStringNoCtx(state, args[0]);
|
|
||||||
return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
ATermMap attrs;
|
|
||||||
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
|
|
||||||
|
|
||||||
ATermList list = evalList(state, args[1]);
|
|
||||||
|
|
||||||
for (ATermIterator i(list); i; ++i)
|
|
||||||
/* It's not an error for *i not to exist. */
|
|
||||||
attrs.remove(toATerm(evalStringNoCtx(state, *i)));
|
|
||||||
|
|
||||||
return makeAttrs(attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primRelativise(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
PathSet context; /* !!! what to do? */
|
|
||||||
Path pivot = coerceToPath(state, args[0], context);
|
|
||||||
Path path = coerceToPath(state, args[1], context);
|
|
||||||
return makeStr(relativise(pivot, path));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primAdd(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
int i1 = evalInt(state, args[0]);
|
|
||||||
int i2 = evalInt(state, args[1]);
|
|
||||||
return makeInt(i1 + i2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primSub(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
int i1 = evalInt(state, args[0]);
|
|
||||||
int i2 = evalInt(state, args[1]);
|
|
||||||
return makeInt(i1 - i2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Expr primLessThan(EvalState & state, const ATermVector & args)
|
|
||||||
{
|
|
||||||
int i1 = evalInt(state, args[0]);
|
|
||||||
int i2 = evalInt(state, args[1]);
|
|
||||||
return makeBool(i1 < i2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct FilterFromExpr : PathFilter
|
struct FilterFromExpr : PathFilter
|
||||||
{
|
{
|
||||||
EvalState & state;
|
EvalState & state;
|
||||||
|
@ -787,6 +694,139 @@ static Expr primFilterSource(EvalState & state, const ATermVector & args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Attribute sets
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the names of the attributes in an attribute set as a sorted
|
||||||
|
list of strings. */
|
||||||
|
static Expr primAttrNames(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
ATermMap attrs;
|
||||||
|
queryAllAttrs(evalExpr(state, args[0]), attrs);
|
||||||
|
|
||||||
|
StringSet names;
|
||||||
|
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
|
||||||
|
names.insert(aterm2String(i->key));
|
||||||
|
|
||||||
|
ATermList list = ATempty;
|
||||||
|
for (StringSet::const_reverse_iterator i = names.rbegin();
|
||||||
|
i != names.rend(); ++i)
|
||||||
|
list = ATinsert(list, makeStr(*i, PathSet()));
|
||||||
|
|
||||||
|
return makeList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Dynamic version of the `.' operator. */
|
||||||
|
static Expr primGetAttr(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
string attr = evalStringNoCtx(state, args[0]);
|
||||||
|
return evalExpr(state, makeSelect(args[1], toATerm(attr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Dynamic version of the `?' operator. */
|
||||||
|
static Expr primHasAttr(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
string attr = evalStringNoCtx(state, args[0]);
|
||||||
|
return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
ATermMap attrs;
|
||||||
|
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
|
||||||
|
|
||||||
|
ATermList list = evalList(state, args[1]);
|
||||||
|
|
||||||
|
for (ATermIterator i(list); i; ++i)
|
||||||
|
/* It's not an error for *i not to exist. */
|
||||||
|
attrs.remove(toATerm(evalStringNoCtx(state, *i)));
|
||||||
|
|
||||||
|
return makeAttrs(attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Lists
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* Determine whether the argument is a list. */
|
||||||
|
static Expr primIsList(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
ATermList list;
|
||||||
|
return makeBool(matchList(evalExpr(state, args[0]), list));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the first element of a list. */
|
||||||
|
static Expr primHead(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
ATermList list = evalList(state, args[0]);
|
||||||
|
if (ATisEmpty(list))
|
||||||
|
throw Error("`head' called on an empty list");
|
||||||
|
return evalExpr(state, ATgetFirst(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return a list consisting of everything but the the first element of
|
||||||
|
a list. */
|
||||||
|
static Expr primTail(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
ATermList list = evalList(state, args[0]);
|
||||||
|
if (ATisEmpty(list))
|
||||||
|
throw Error("`tail' called on an empty list");
|
||||||
|
return makeList(ATgetNext(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Apply a function to every element of a list. */
|
||||||
|
static Expr primMap(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
Expr fun = evalExpr(state, args[0]);
|
||||||
|
ATermList list = evalList(state, args[1]);
|
||||||
|
|
||||||
|
ATermList res = ATempty;
|
||||||
|
for (ATermIterator i(list); i; ++i)
|
||||||
|
res = ATinsert(res, makeCall(fun, *i));
|
||||||
|
|
||||||
|
return makeList(ATreverse(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* Integer arithmetic
|
||||||
|
*************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primAdd(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
int i1 = evalInt(state, args[0]);
|
||||||
|
int i2 = evalInt(state, args[1]);
|
||||||
|
return makeInt(i1 + i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primSub(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
int i1 = evalInt(state, args[0]);
|
||||||
|
int i2 = evalInt(state, args[1]);
|
||||||
|
return makeInt(i1 - i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Expr primLessThan(EvalState & state, const ATermVector & args)
|
||||||
|
{
|
||||||
|
int i1 = evalInt(state, args[0]);
|
||||||
|
int i2 = evalInt(state, args[1]);
|
||||||
|
return makeBool(i1 < i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* String manipulation
|
* String manipulation
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
@ -821,41 +861,56 @@ void EvalState::addPrimOps()
|
||||||
{
|
{
|
||||||
addPrimOp("builtins", 0, primBuiltins);
|
addPrimOp("builtins", 0, primBuiltins);
|
||||||
|
|
||||||
|
// Constants
|
||||||
addPrimOp("true", 0, primTrue);
|
addPrimOp("true", 0, primTrue);
|
||||||
addPrimOp("false", 0, primFalse);
|
addPrimOp("false", 0, primFalse);
|
||||||
addPrimOp("null", 0, primNull);
|
addPrimOp("null", 0, primNull);
|
||||||
addPrimOp("__currentSystem", 0, primCurrentSystem);
|
addPrimOp("__currentSystem", 0, primCurrentSystem);
|
||||||
addPrimOp("__currentTime", 0, primCurrentTime);
|
addPrimOp("__currentTime", 0, primCurrentTime);
|
||||||
|
|
||||||
|
// Miscellaneous
|
||||||
addPrimOp("import", 1, primImport);
|
addPrimOp("import", 1, primImport);
|
||||||
addPrimOp("__pathExists", 1, primPathExists);
|
|
||||||
addPrimOp("derivation!", 1, primDerivationStrict);
|
|
||||||
addPrimOp("derivation", 1, primDerivationLazy);
|
|
||||||
addPrimOp("baseNameOf", 1, primBaseNameOf);
|
|
||||||
addPrimOp("dirOf", 1, primDirOf);
|
|
||||||
addPrimOp("toString", 1, primToString);
|
addPrimOp("toString", 1, primToString);
|
||||||
addPrimOp("__toPath", 1, primToPath);
|
|
||||||
addPrimOp("__toXML", 1, primToXML);
|
|
||||||
addPrimOp("isNull", 1, primIsNull);
|
addPrimOp("isNull", 1, primIsNull);
|
||||||
addPrimOp("__isList", 1, primIsList);
|
|
||||||
addPrimOp("dependencyClosure", 1, primDependencyClosure);
|
addPrimOp("dependencyClosure", 1, primDependencyClosure);
|
||||||
addPrimOp("abort", 1, primAbort);
|
addPrimOp("abort", 1, primAbort);
|
||||||
addPrimOp("__head", 1, primHead);
|
|
||||||
addPrimOp("__tail", 1, primTail);
|
|
||||||
addPrimOp("__getEnv", 1, primGetEnv);
|
addPrimOp("__getEnv", 1, primGetEnv);
|
||||||
addPrimOp("__attrNames", 1, primAttrNames);
|
|
||||||
|
|
||||||
addPrimOp("map", 2, primMap);
|
|
||||||
addPrimOp("__getAttr", 2, primGetAttr);
|
|
||||||
addPrimOp("__hasAttr", 2, primHasAttr);
|
|
||||||
addPrimOp("removeAttrs", 2, primRemoveAttrs);
|
|
||||||
addPrimOp("relativise", 2, primRelativise);
|
addPrimOp("relativise", 2, primRelativise);
|
||||||
addPrimOp("__add", 2, primAdd);
|
|
||||||
addPrimOp("__sub", 2, primSub);
|
// Derivations
|
||||||
addPrimOp("__lessThan", 2, primLessThan);
|
addPrimOp("derivation!", 1, primDerivationStrict);
|
||||||
|
addPrimOp("derivation", 1, primDerivationLazy);
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
addPrimOp("__toPath", 1, primToPath);
|
||||||
|
addPrimOp("__pathExists", 1, primPathExists);
|
||||||
|
addPrimOp("baseNameOf", 1, primBaseNameOf);
|
||||||
|
addPrimOp("dirOf", 1, primDirOf);
|
||||||
|
|
||||||
|
// Creating files
|
||||||
|
addPrimOp("__toXML", 1, primToXML);
|
||||||
addPrimOp("__toFile", 2, primToFile);
|
addPrimOp("__toFile", 2, primToFile);
|
||||||
addPrimOp("__filterSource", 2, primFilterSource);
|
addPrimOp("__filterSource", 2, primFilterSource);
|
||||||
|
|
||||||
|
// Attribute sets
|
||||||
|
addPrimOp("__attrNames", 1, primAttrNames);
|
||||||
|
addPrimOp("__getAttr", 2, primGetAttr);
|
||||||
|
addPrimOp("__hasAttr", 2, primHasAttr);
|
||||||
|
addPrimOp("removeAttrs", 2, primRemoveAttrs);
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
addPrimOp("__isList", 1, primIsList);
|
||||||
|
addPrimOp("__head", 1, primHead);
|
||||||
|
addPrimOp("__tail", 1, primTail);
|
||||||
|
addPrimOp("map", 2, primMap);
|
||||||
|
|
||||||
|
// Integer arithmetic
|
||||||
|
addPrimOp("__add", 2, primAdd);
|
||||||
|
addPrimOp("__sub", 2, primSub);
|
||||||
|
addPrimOp("__lessThan", 2, primLessThan);
|
||||||
|
|
||||||
|
// String manipulation
|
||||||
addPrimOp("__substring", 3, prim_substring);
|
addPrimOp("__substring", 3, prim_substring);
|
||||||
addPrimOp("__stringLength", 1, prim_stringLength);
|
addPrimOp("__stringLength", 1, prim_stringLength);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue