mirror of
https://github.com/NixOS/nix.git
synced 2025-11-10 04:26:01 +01:00
* Don't use ATmake / ATmatch anymore, nor the ATMatcher class.
Instead we generate data bindings (build and match functions) for the constructors specified in `constructors.def'. In particular this removes the conversions between AFuns and strings, and Nix expression evaluation now seems 3 to 4 times faster.
This commit is contained in:
parent
eb8284ddaa
commit
5fe9222b36
11 changed files with 410 additions and 304 deletions
|
|
@ -1,15 +1,17 @@
|
|||
#include "eval.hh"
|
||||
#include "parser.hh"
|
||||
#include "constructors.hh"
|
||||
|
||||
|
||||
EvalState::EvalState()
|
||||
: normalForms(32768, 50)
|
||||
{
|
||||
blackHole = ATmake("BlackHole()");
|
||||
if (!blackHole) throw Error("cannot build black hole");
|
||||
blackHole = makeBlackHole();
|
||||
|
||||
nrEvaluated = nrCached = 0;
|
||||
|
||||
initSyms();
|
||||
|
||||
addPrimOps();
|
||||
}
|
||||
|
||||
|
|
@ -17,24 +19,22 @@ EvalState::EvalState()
|
|||
void EvalState::addPrimOp(const string & name,
|
||||
unsigned int arity, PrimOp primOp)
|
||||
{
|
||||
primOps.set(name, ATmake("(<int>, <term>)",
|
||||
arity, ATmakeBlob(0, (void *) primOp)));
|
||||
primOps.set(name, makePrimOpDef(arity, ATmakeBlob(0, (void *) primOp)));
|
||||
}
|
||||
|
||||
|
||||
/* Substitute an argument set into the body of a function. */
|
||||
static Expr substArgs(Expr body, ATermList formals, Expr arg)
|
||||
{
|
||||
ATMatcher m;
|
||||
ATermMap subs;
|
||||
Expr undefined = ATmake("Undefined");
|
||||
Expr undefined = makeUndefined();
|
||||
|
||||
/* Get the formal arguments. */
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
Expr name, def;
|
||||
if (atMatch(m, *i) >> "NoDefFormal" >> name)
|
||||
if (matchNoDefFormal(*i, name))
|
||||
subs.set(name, undefined);
|
||||
else if (atMatch(m, *i) >> "DefFormal" >> name >> def)
|
||||
else if (matchDefFormal(*i, name, def))
|
||||
subs.set(name, def);
|
||||
else abort(); /* can't happen */
|
||||
}
|
||||
|
|
@ -69,38 +69,32 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg)
|
|||
(e.x) (e.y); y = e.x;}'. */
|
||||
ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
|
||||
{
|
||||
ATMatcher m;
|
||||
ATerm name;
|
||||
Expr e2;
|
||||
Pos pos;
|
||||
|
||||
/* Create the substitution list. */
|
||||
ATermMap subs;
|
||||
for (ATermIterator i(rbnds); i; ++i) {
|
||||
if (!(atMatch(m, *i) >> "Bind" >> name >> e2))
|
||||
abort(); /* can't happen */
|
||||
subs.set(name, ATmake("Select(<term>, <term>)", e, name));
|
||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
||||
subs.set(name, makeSelect(e, name));
|
||||
}
|
||||
for (ATermIterator i(nrbnds); i; ++i) {
|
||||
if (!(atMatch(m, *i) >> "Bind" >> name >> e2))
|
||||
abort(); /* can't happen */
|
||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
||||
subs.set(name, e2);
|
||||
}
|
||||
|
||||
/* Create the non-recursive set. */
|
||||
ATermMap as;
|
||||
for (ATermIterator i(rbnds); i; ++i) {
|
||||
ATerm pos;
|
||||
if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos))
|
||||
abort(); /* can't happen */
|
||||
as.set(name, ATmake("(<term>, <term>)", substitute(subs, e2), pos));
|
||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
||||
as.set(name, makeAttrRHS(substitute(subs, e2), pos));
|
||||
}
|
||||
|
||||
/* Copy the non-recursive bindings. !!! inefficient */
|
||||
for (ATermIterator i(nrbnds); i; ++i) {
|
||||
ATerm pos;
|
||||
if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos))
|
||||
abort(); /* can't happen */
|
||||
as.set(name, ATmake("(<term>, <term>)", e2, pos));
|
||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
||||
as.set(name, makeAttrRHS(e2, pos));
|
||||
}
|
||||
|
||||
return makeAttrs(as);
|
||||
|
|
@ -122,82 +116,73 @@ static Expr updateAttrs(Expr e1, Expr e2)
|
|||
string evalString(EvalState & state, Expr e)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
ATMatcher m;
|
||||
string s;
|
||||
if (!(atMatch(m, e) >> "Str" >> s))
|
||||
throw Error("string expected");
|
||||
return s;
|
||||
ATerm s;
|
||||
if (!matchStr(e, s)) throw Error("string expected");
|
||||
return aterm2String(s);
|
||||
}
|
||||
|
||||
|
||||
Path evalPath(EvalState & state, Expr e)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
ATMatcher m;
|
||||
string s;
|
||||
if (!(atMatch(m, e) >> "Path" >> s))
|
||||
throw Error("path expected");
|
||||
return s;
|
||||
ATerm s;
|
||||
if (!matchPath(e, s)) throw Error("path expected");
|
||||
return aterm2String(s);
|
||||
}
|
||||
|
||||
|
||||
bool evalBool(EvalState & state, Expr e)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
ATMatcher m;
|
||||
if (atMatch(m, e) >> "Bool" >> "True") return true;
|
||||
else if (atMatch(m, e) >> "Bool" >> "False") return false;
|
||||
if (e == eTrue) return true;
|
||||
else if (e == eFalse) return false;
|
||||
else throw Error("boolean expected");
|
||||
}
|
||||
|
||||
|
||||
Expr evalExpr2(EvalState & state, Expr e)
|
||||
{
|
||||
ATMatcher m;
|
||||
Expr e1, e2, e3, e4;
|
||||
ATerm name, pos;
|
||||
AFun sym = ATgetAFun(e);
|
||||
|
||||
/* Normal forms. */
|
||||
string cons;
|
||||
if (atMatch(m, e) >> cons &&
|
||||
(cons == "Str" ||
|
||||
cons == "Path" ||
|
||||
cons == "SubPath" ||
|
||||
cons == "Uri" ||
|
||||
cons == "Null" ||
|
||||
cons == "Int" ||
|
||||
cons == "Bool" ||
|
||||
cons == "Function" ||
|
||||
cons == "Function1" ||
|
||||
cons == "Attrs" ||
|
||||
cons == "List" ||
|
||||
cons == "PrimOp"))
|
||||
if (sym == symStr ||
|
||||
sym == symPath ||
|
||||
sym == symSubPath ||
|
||||
sym == symUri ||
|
||||
sym == symNull ||
|
||||
sym == symInt ||
|
||||
sym == symBool ||
|
||||
sym == symFunction ||
|
||||
sym == symFunction1 ||
|
||||
sym == symAttrs ||
|
||||
sym == symList ||
|
||||
sym == symPrimOp)
|
||||
return e;
|
||||
|
||||
|
||||
/* The `Closed' constructor is just a way to prevent substitutions
|
||||
into expressions not containing free variables. */
|
||||
if (atMatch(m, e) >> "Closed" >> e1)
|
||||
if (matchClosed(e, e1))
|
||||
return evalExpr(state, e1);
|
||||
|
||||
/* Any encountered variables must be primops (since undefined
|
||||
variables are detected after parsing). */
|
||||
if (atMatch(m, e) >> "Var" >> name) {
|
||||
if (matchVar(e, name)) {
|
||||
ATerm primOp = state.primOps.get(name);
|
||||
if (!primOp)
|
||||
throw Error(format("impossible: undefined variable `%1%'") % name);
|
||||
int arity;
|
||||
ATerm fun;
|
||||
if (!(atMatch(m, primOp) >> "" >> arity >> fun)) abort();
|
||||
ATermBlob fun;
|
||||
if (!matchPrimOpDef(primOp, arity, fun)) abort();
|
||||
if (arity == 0)
|
||||
return ((PrimOp) ATgetBlobData((ATermBlob) fun))
|
||||
(state, ATermVector());
|
||||
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
|
||||
else
|
||||
return ATmake("PrimOp(<int>, <term>, <term>)",
|
||||
arity, fun, ATempty);
|
||||
return makePrimOp(arity, fun, ATempty);
|
||||
}
|
||||
|
||||
/* Function application. */
|
||||
if (atMatch(m, e) >> "Call" >> e1 >> e2) {
|
||||
if (matchCall(e, e1, e2)) {
|
||||
|
||||
ATermList formals;
|
||||
ATerm pos;
|
||||
|
|
@ -207,9 +192,9 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
|
||||
/* Is it a primop or a function? */
|
||||
int arity;
|
||||
ATerm fun;
|
||||
ATermBlob fun;
|
||||
ATermList args;
|
||||
if (atMatch(m, e1) >> "PrimOp" >> arity >> fun >> args) {
|
||||
if (matchPrimOp(e1, arity, fun, args)) {
|
||||
args = ATinsert(args, e2);
|
||||
if (ATgetLength(args) == arity) {
|
||||
/* Put the arguments in a vector in reverse (i.e.,
|
||||
|
|
@ -221,11 +206,10 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
(state, args2);
|
||||
} else
|
||||
/* Need more arguments, so propagate the primop. */
|
||||
return ATmake("PrimOp(<int>, <term>, <term>)",
|
||||
arity, fun, args);
|
||||
return makePrimOp(arity, fun, args);
|
||||
}
|
||||
|
||||
else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) {
|
||||
else if (matchFunction(e1, formals, e4, pos)) {
|
||||
e2 = evalExpr(state, e2);
|
||||
try {
|
||||
return evalExpr(state, substArgs(e4, formals, e2));
|
||||
|
|
@ -235,7 +219,7 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
}
|
||||
}
|
||||
|
||||
else if (atMatch(m, e1) >> "Function1" >> name >> e4 >> pos) {
|
||||
else if (matchFunction1(e1, name, e4, pos)) {
|
||||
try {
|
||||
ATermMap subs;
|
||||
subs.set(name, e2);
|
||||
|
|
@ -250,9 +234,9 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
}
|
||||
|
||||
/* Attribute selection. */
|
||||
string s1;
|
||||
if (atMatch(m, e) >> "Select" >> e1 >> s1) {
|
||||
if (matchSelect(e, e1, name)) {
|
||||
ATerm pos;
|
||||
string s1 = aterm2String(name);
|
||||
Expr a = queryAttr(evalExpr(state, e1), s1, pos);
|
||||
if (!a) throw Error(format("attribute `%1%' missing") % s1);
|
||||
try {
|
||||
|
|
@ -265,11 +249,11 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
|
||||
/* Mutually recursive sets. */
|
||||
ATermList rbnds, nrbnds;
|
||||
if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds)
|
||||
if (matchRec(e, rbnds, nrbnds))
|
||||
return expandRec(e, rbnds, nrbnds);
|
||||
|
||||
/* Conditionals. */
|
||||
if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) {
|
||||
if (matchIf(e, e1, e2, e3)) {
|
||||
if (evalBool(state, e1))
|
||||
return evalExpr(state, e2);
|
||||
else
|
||||
|
|
@ -277,14 +261,14 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
}
|
||||
|
||||
/* Assertions. */
|
||||
if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) {
|
||||
if (matchAssert(e, e1, e2, pos)) {
|
||||
if (!evalBool(state, e1))
|
||||
throw Error(format("assertion failed at %1%") % showPos(pos));
|
||||
return evalExpr(state, e2);
|
||||
}
|
||||
|
||||
/* Withs. */
|
||||
if (atMatch(m, e) >> "With" >> e1 >> e2 >> pos) {
|
||||
if (matchWith(e, e1, e2, pos)) {
|
||||
ATermMap attrs;
|
||||
try {
|
||||
e1 = evalExpr(state, e1);
|
||||
|
|
@ -304,51 +288,51 @@ Expr evalExpr2(EvalState & state, Expr e)
|
|||
}
|
||||
|
||||
/* Generic equality. */
|
||||
if (atMatch(m, e) >> "OpEq" >> e1 >> e2)
|
||||
if (matchOpEq(e, e1, e2))
|
||||
return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
|
||||
|
||||
/* Generic inequality. */
|
||||
if (atMatch(m, e) >> "OpNEq" >> e1 >> e2)
|
||||
if (matchOpNEq(e, e1, e2))
|
||||
return makeBool(evalExpr(state, e1) != evalExpr(state, e2));
|
||||
|
||||
/* Negation. */
|
||||
if (atMatch(m, e) >> "OpNot" >> e1)
|
||||
if (matchOpNot(e, e1))
|
||||
return makeBool(!evalBool(state, e1));
|
||||
|
||||
/* Implication. */
|
||||
if (atMatch(m, e) >> "OpImpl" >> e1 >> e2)
|
||||
if (matchOpImpl(e, e1, e2))
|
||||
return makeBool(!evalBool(state, e1) || evalBool(state, e2));
|
||||
|
||||
/* Conjunction (logical AND). */
|
||||
if (atMatch(m, e) >> "OpAnd" >> e1 >> e2)
|
||||
if (matchOpAnd(e, e1, e2))
|
||||
return makeBool(evalBool(state, e1) && evalBool(state, e2));
|
||||
|
||||
/* Disjunction (logical OR). */
|
||||
if (atMatch(m, e) >> "OpOr" >> e1 >> e2)
|
||||
if (matchOpOr(e, e1, e2))
|
||||
return makeBool(evalBool(state, e1) || evalBool(state, e2));
|
||||
|
||||
/* Attribute set update (//). */
|
||||
if (atMatch(m, e) >> "OpUpdate" >> e1 >> e2)
|
||||
if (matchOpUpdate(e, e1, e2))
|
||||
return updateAttrs(evalExpr(state, e1), evalExpr(state, e2));
|
||||
|
||||
/* Attribute existence test (?). */
|
||||
if (atMatch(m, e) >> "OpHasAttr" >> e1 >> name) {
|
||||
if (matchOpHasAttr(e, e1, name)) {
|
||||
ATermMap attrs;
|
||||
queryAllAttrs(evalExpr(state, e1), attrs);
|
||||
return makeBool(attrs.get(name) != 0);
|
||||
}
|
||||
|
||||
/* String or path concatenation. */
|
||||
if (atMatch(m, e) >> "OpPlus" >> e1 >> e2) {
|
||||
if (matchOpPlus(e, e1, e2)) {
|
||||
e1 = evalExpr(state, e1);
|
||||
e2 = evalExpr(state, e2);
|
||||
string s1, s2;
|
||||
if (atMatch(m, e1) >> "Str" >> s1 &&
|
||||
atMatch(m, e2) >> "Str" >> s2)
|
||||
return makeString(s1 + s2);
|
||||
else if (atMatch(m, e1) >> "Path" >> s1 &&
|
||||
atMatch(m, e2) >> "Path" >> s2)
|
||||
return makePath(canonPath(s1 + "/" + s2));
|
||||
ATerm s1, s2;
|
||||
if (matchStr(e1, s1) && matchStr(e2, s2))
|
||||
return makeStr(string2ATerm((
|
||||
(string) aterm2String(s1) + (string) aterm2String(s2)).c_str()));
|
||||
else if (matchPath(e1, s1) && matchPath(e2, s2))
|
||||
return makePath(string2ATerm(canonPath(
|
||||
(string) aterm2String(s1) + "/" + (string) aterm2String(s2)).c_str()));
|
||||
else throw Error("wrong argument types in `+' operator");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue