nix-gh/src/libnix/expr.cc

231 lines
6 KiB
C++
Raw Normal View History

#include "expr.hh"
#include "globals.hh"
2003-07-07 09:43:58 +02:00
#include "store.hh"
string printTerm(ATerm t)
2003-06-17 15:37:44 +02:00
{
char * s = ATwriteToString(t);
if (!s) throw Error("cannot print term");
2003-06-17 15:37:44 +02:00
return s;
}
2003-07-06 16:20:47 +02:00
Error badTerm(const format & f, ATerm t)
{
char * s = ATwriteToString(t);
if (!s) throw Error("cannot print term");
if (strlen(s) > 1000) {
int len;
s = ATwriteToSharedString(t, &len);
if (!s) throw Error("cannot print term");
}
return Error(format("%1%, in `%2%'") % f.str() % (string) s);
}
Hash hashTerm(ATerm t)
{
return hashString(printTerm(t));
}
Path writeTerm(ATerm t, const string & suffix)
2003-07-04 14:18:06 +02:00
{
/* The id of a term is its hash. */
Hash h = hashTerm(t);
Path path = canonPath(nixStore + "/" +
(string) h + suffix + ".nix");
if (!isValidPath(path)) {
char * s = ATwriteToString(t);
if (!s) throw Error(format("cannot write aterm to `%1%'") % path);
addTextToStore(path, string(s));
}
return path;
2003-07-04 14:18:06 +02:00
}
static void parsePaths(ATermList paths, PathSet & out)
{
while (!ATisEmpty(paths)) {
char * s;
ATerm t = ATgetFirst(paths);
if (!ATmatch(t, "<str>", &s))
throw badTerm("not a path", t);
out.insert(s);
paths = ATgetNext(paths);
}
}
static void checkClosure(const Closure & closure)
2003-07-20 21:29:38 +02:00
{
if (closure.elems.size() == 0)
throw Error("empty closure");
2003-07-20 21:29:38 +02:00
PathSet decl;
for (ClosureElems::const_iterator i = closure.elems.begin();
i != closure.elems.end(); i++)
decl.insert(i->first);
2003-07-20 21:29:38 +02:00
for (PathSet::const_iterator i = closure.roots.begin();
i != closure.roots.end(); i++)
2003-07-20 21:29:38 +02:00
if (decl.find(*i) == decl.end())
throw Error(format("undefined root path `%1%'") % *i);
2003-07-20 21:29:38 +02:00
for (ClosureElems::const_iterator i = closure.elems.begin();
i != closure.elems.end(); i++)
for (PathSet::const_iterator j = i->second.refs.begin();
j != i->second.refs.end(); j++)
2003-07-20 21:29:38 +02:00
if (decl.find(*j) == decl.end())
throw Error(
format("undefined path `%1%' referenced by `%2%'")
% *j % i->first);
2003-07-20 21:29:38 +02:00
}
/* Parse a closure. */
static bool parseClosure(ATerm t, Closure & closure)
{
ATermList roots, elems;
if (!ATmatch(t, "Closure([<list>], [<list>])", &roots, &elems))
2003-07-20 21:29:38 +02:00
return false;
parsePaths(roots, closure.roots);
while (!ATisEmpty(elems)) {
char * s1;
ATermList refs;
ATerm t = ATgetFirst(elems);
if (!ATmatch(t, "(<str>, [<list>])", &s1, &refs))
throw badTerm("not a closure element", t);
ClosureElem elem;
parsePaths(refs, elem.refs);
closure.elems[s1] = elem;
elems = ATgetNext(elems);
}
checkClosure(closure);
2003-07-20 21:29:38 +02:00
return true;
}
static bool parseDerivation(ATerm t, Derivation & derivation)
{
ATermList outs, ins, args, bnds;
char * builder;
char * platform;
if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>], [<list>])",
&outs, &ins, &platform, &builder, &args, &bnds))
{
/* !!! compatibility -> remove eventually */
if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>])",
&outs, &ins, &builder, &platform, &bnds))
return false;
args = ATempty;
}
parsePaths(outs, derivation.outputs);
parsePaths(ins, derivation.inputs);
derivation.builder = builder;
derivation.platform = platform;
2003-07-20 21:29:38 +02:00
while (!ATisEmpty(args)) {
char * s;
ATerm arg = ATgetFirst(args);
if (!ATmatch(arg, "<str>", &s))
throw badTerm("string expected", arg);
derivation.args.push_back(s);
args = ATgetNext(args);
}
while (!ATisEmpty(bnds)) {
char * s1, * s2;
ATerm bnd = ATgetFirst(bnds);
if (!ATmatch(bnd, "(<str>, <str>)", &s1, &s2))
throw badTerm("tuple of strings expected", bnd);
derivation.env[s1] = s2;
bnds = ATgetNext(bnds);
}
2003-07-20 21:29:38 +02:00
return true;
}
NixExpr parseNixExpr(ATerm t)
2003-07-16 13:05:59 +02:00
{
NixExpr ne;
if (parseClosure(t, ne.closure))
ne.type = NixExpr::neClosure;
else if (parseDerivation(t, ne.derivation))
ne.type = NixExpr::neDerivation;
else throw badTerm("not a Nix expression", t);
return ne;
2003-07-16 13:05:59 +02:00
}
static ATermList unparsePaths(const PathSet & paths)
{
2003-07-20 21:29:38 +02:00
ATermList l = ATempty;
for (PathSet::const_iterator i = paths.begin();
i != paths.end(); i++)
l = ATinsert(l, ATmake("<str>", i->c_str()));
2003-07-20 21:29:38 +02:00
return ATreverse(l);
}
static ATerm unparseClosure(const Closure & closure)
{
ATermList roots = unparsePaths(closure.roots);
2003-07-20 21:29:38 +02:00
ATermList elems = ATempty;
for (ClosureElems::const_iterator i = closure.elems.begin();
i != closure.elems.end(); i++)
2003-07-20 21:29:38 +02:00
elems = ATinsert(elems,
ATmake("(<str>, <term>)",
i->first.c_str(),
unparsePaths(i->second.refs)));
return ATmake("Closure(<term>, <term>)", roots, elems);
}
2003-07-16 00:28:27 +02:00
static ATerm unparseDerivation(const Derivation & derivation)
2003-07-16 00:28:27 +02:00
{
ATermList args = ATempty;
for (Strings::const_iterator i = derivation.args.begin();
i != derivation.args.end(); i++)
args = ATinsert(args, ATmake("<str>", i->c_str()));
2003-07-20 21:29:38 +02:00
ATermList env = ATempty;
for (StringPairs::const_iterator i = derivation.env.begin();
i != derivation.env.end(); i++)
2003-07-20 21:29:38 +02:00
env = ATinsert(env,
ATmake("(<str>, <str>)",
i->first.c_str(), i->second.c_str()));
2003-07-16 00:28:27 +02:00
return ATmake("Derive(<term>, <term>, <str>, <str>, <term>, <term>)",
unparsePaths(derivation.outputs),
unparsePaths(derivation.inputs),
derivation.platform.c_str(),
derivation.builder.c_str(),
ATreverse(args),
2003-07-20 21:29:38 +02:00
ATreverse(env));
2003-07-16 00:28:27 +02:00
}
2003-07-16 13:05:59 +02:00
ATerm unparseNixExpr(const NixExpr & ne)
2003-07-16 13:05:59 +02:00
{
if (ne.type == NixExpr::neClosure)
return unparseClosure(ne.closure);
else if (ne.type == NixExpr::neDerivation)
return unparseDerivation(ne.derivation);
2003-07-20 21:29:38 +02:00
else abort();
2003-07-16 13:05:59 +02:00
}