forked from lix-project/lix
447089a5f6
Nix. This is to prevent Berkeley DB from becoming wedged. Unfortunately it is not possible to throw C++ exceptions from a signal handler. In fact, you can't do much of anything except change variables of type `volatile sig_atomic_t'. So we set an interrupt flag in the signal handler and check it at various strategic locations in the code (by calling checkInterrupt()). Since this is unlikely to cover all cases (e.g., (semi-)infinite loops), sometimes SIGTERM may now be required to kill Nix.
220 lines
4.7 KiB
C++
220 lines
4.7 KiB
C++
#include "nixexpr.hh"
|
|
#include "storeexpr.hh"
|
|
|
|
|
|
ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct)
|
|
{
|
|
table = ATtableCreate(initialSize, maxLoadPct);
|
|
if (!table) throw Error("cannot create ATerm table");
|
|
}
|
|
|
|
|
|
ATermMap::ATermMap(const ATermMap & map)
|
|
: table(0)
|
|
{
|
|
ATermList keys = map.keys();
|
|
|
|
/* !!! adjust allocation for load pct */
|
|
table = ATtableCreate(ATgetLength(keys), map.maxLoadPct);
|
|
if (!table) throw Error("cannot create ATerm table");
|
|
|
|
for (ATermIterator i(keys); i; ++i)
|
|
set(*i, map.get(*i));
|
|
}
|
|
|
|
|
|
ATermMap::~ATermMap()
|
|
{
|
|
if (table) ATtableDestroy(table);
|
|
}
|
|
|
|
|
|
void ATermMap::set(ATerm key, ATerm value)
|
|
{
|
|
return ATtablePut(table, key, value);
|
|
}
|
|
|
|
|
|
void ATermMap::set(const string & key, ATerm value)
|
|
{
|
|
set(string2ATerm(key), value);
|
|
}
|
|
|
|
|
|
ATerm ATermMap::get(ATerm key) const
|
|
{
|
|
return ATtableGet(table, key);
|
|
}
|
|
|
|
|
|
ATerm ATermMap::get(const string & key) const
|
|
{
|
|
return get(string2ATerm(key));
|
|
}
|
|
|
|
|
|
void ATermMap::remove(ATerm key)
|
|
{
|
|
ATtableRemove(table, key);
|
|
}
|
|
|
|
|
|
void ATermMap::remove(const string & key)
|
|
{
|
|
remove(string2ATerm(key));
|
|
}
|
|
|
|
|
|
ATermList ATermMap::keys() const
|
|
{
|
|
ATermList keys = ATtableKeys(table);
|
|
if (!keys) throw Error("cannot query aterm map keys");
|
|
return keys;
|
|
}
|
|
|
|
|
|
ATerm string2ATerm(const string & s)
|
|
{
|
|
return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue));
|
|
}
|
|
|
|
|
|
string aterm2String(ATerm t)
|
|
{
|
|
return ATgetName(ATgetAFun(t));
|
|
}
|
|
|
|
|
|
ATerm bottomupRewrite(TermFun & f, ATerm e)
|
|
{
|
|
checkInterrupt();
|
|
|
|
if (ATgetType(e) == AT_APPL) {
|
|
AFun fun = ATgetAFun(e);
|
|
int arity = ATgetArity(fun);
|
|
ATermList args = ATempty;
|
|
|
|
for (int i = arity - 1; i >= 0; i--)
|
|
args = ATinsert(args, bottomupRewrite(f, ATgetArgument(e, i)));
|
|
|
|
e = (ATerm) ATmakeApplList(fun, args);
|
|
}
|
|
|
|
else if (ATgetType(e) == AT_LIST) {
|
|
ATermList in = (ATermList) e;
|
|
ATermList out = ATempty;
|
|
|
|
for (ATermIterator i(in); i; ++i)
|
|
out = ATinsert(out, bottomupRewrite(f, *i));
|
|
|
|
e = (ATerm) ATreverse(out);
|
|
}
|
|
|
|
return f(e);
|
|
}
|
|
|
|
|
|
void queryAllAttrs(Expr e, ATermMap & attrs)
|
|
{
|
|
ATMatcher m;
|
|
ATermList bnds;
|
|
if (!(atMatch(m, e) >> "Attrs" >> bnds))
|
|
throw badTerm("expected attribute set", e);
|
|
|
|
for (ATermIterator i(bnds); i; ++i) {
|
|
string s;
|
|
Expr e;
|
|
if (!(atMatch(m, *i) >> "Bind" >> s >> e))
|
|
abort(); /* can't happen */
|
|
attrs.set(s, e);
|
|
}
|
|
}
|
|
|
|
|
|
Expr queryAttr(Expr e, const string & name)
|
|
{
|
|
ATermMap attrs;
|
|
queryAllAttrs(e, attrs);
|
|
return attrs.get(name);
|
|
}
|
|
|
|
|
|
Expr makeAttrs(const ATermMap & attrs)
|
|
{
|
|
ATermList bnds = ATempty;
|
|
for (ATermIterator i(attrs.keys()); i; ++i)
|
|
bnds = ATinsert(bnds,
|
|
ATmake("Bind(<term>, <term>)", *i, attrs.get(*i)));
|
|
return ATmake("Attrs(<term>)", ATreverse(bnds));
|
|
}
|
|
|
|
|
|
Expr substitute(const ATermMap & subs, Expr e)
|
|
{
|
|
checkInterrupt();
|
|
|
|
ATMatcher m;
|
|
string s;
|
|
|
|
if (atMatch(m, e) >> "Var" >> s) {
|
|
Expr sub = subs.get(s);
|
|
return sub ? sub : e;
|
|
}
|
|
|
|
/* In case of a function, filter out all variables bound by this
|
|
function. */
|
|
ATermList formals;
|
|
ATerm body;
|
|
if (atMatch(m, e) >> "Function" >> formals >> body) {
|
|
ATermMap subs2(subs);
|
|
for (ATermIterator i(formals); i; ++i) {
|
|
Expr def;
|
|
if (!(atMatch(m, *i) >> "NoDefFormal" >> s) &&
|
|
!(atMatch(m, *i) >> "DefFormal" >> s >> def))
|
|
abort();
|
|
subs2.remove(s);
|
|
}
|
|
return ATmake("Function(<term>, <term>)", formals,
|
|
substitute(subs2, body));
|
|
}
|
|
|
|
/* Idem for a mutually recursive attribute set. */
|
|
ATermList bindings;
|
|
if (atMatch(m, e) >> "Rec" >> bindings) {
|
|
ATermMap subs2(subs);
|
|
for (ATermIterator i(bindings); i; ++i) {
|
|
Expr e;
|
|
if (!(atMatch(m, *i) >> "Bind" >> s >> e))
|
|
abort(); /* can't happen */
|
|
subs2.remove(s);
|
|
}
|
|
return ATmake("Rec(<term>)", substitute(subs2, (ATerm) bindings));
|
|
}
|
|
|
|
if (ATgetType(e) == AT_APPL) {
|
|
AFun fun = ATgetAFun(e);
|
|
int arity = ATgetArity(fun);
|
|
ATermList args = ATempty;
|
|
|
|
for (int i = arity - 1; i >= 0; i--)
|
|
args = ATinsert(args, substitute(subs, ATgetArgument(e, i)));
|
|
|
|
return (ATerm) ATmakeApplList(fun, args);
|
|
}
|
|
|
|
if (ATgetType(e) == AT_LIST) {
|
|
ATermList out = ATempty;
|
|
for (ATermIterator i((ATermList) e); i; ++i)
|
|
out = ATinsert(out, substitute(subs, *i));
|
|
return (ATerm) ATreverse(out);
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
|
|
Expr makeBool(bool b)
|
|
{
|
|
return b ? ATmake("Bool(True)") : ATmake("Bool(False)");
|
|
}
|