* Use a map to lookup primops.

* Various performance improvements in the evaluator.
* Do not link against unused (and missing!) libraries (-lsglr, etc.).
This commit is contained in:
Eelco Dolstra 2004-02-04 16:03:29 +00:00
parent c4f7ae4aa5
commit 9b44480612
12 changed files with 127 additions and 75 deletions

View file

@ -3,12 +3,52 @@
#include "primops.hh" #include "primops.hh"
static void addPrimOp(ATermMap & map, const string & name, void * f)
{
map.set(name, (ATerm) ATmakeBlob(0, f));
}
static void * lookupPrimOp(ATermMap & map, ATerm name)
{
ATermBlob b = (ATermBlob) map.get(name);
if (!b) return 0;
return ATgetBlobData(b);
}
EvalState::EvalState() EvalState::EvalState()
: normalForms(32768, 75) : normalForms(32768, 50)
{ {
blackHole = ATmake("BlackHole()"); blackHole = ATmake("BlackHole()");
if (!blackHole) throw Error("cannot build black hole"); if (!blackHole) throw Error("cannot build black hole");
nrEvaluated = nrCached = 0; nrEvaluated = nrCached = 0;
addPrimOp0("true", primTrue);
addPrimOp0("false", primFalse);
addPrimOp0("null", primNull);
addPrimOp1("import", primImport);
addPrimOp1("derivation", primDerivation);
addPrimOp1("baseNameOf", primBaseNameOf);
addPrimOp1("toString", primToString);
addPrimOp1("isNull", primIsNull);
primOpsAll.add(primOps0);
primOpsAll.add(primOps1);
}
void EvalState::addPrimOp0(const string & name, PrimOp0 primOp)
{
addPrimOp(primOps0, name, (void *) primOp);
}
void EvalState::addPrimOp1(const string & name, PrimOp1 primOp)
{
addPrimOp(primOps1, name, (void *) primOp);
} }
@ -130,7 +170,7 @@ Expr evalExpr2(EvalState & state, Expr e)
{ {
ATMatcher m; ATMatcher m;
Expr e1, e2, e3, e4; Expr e1, e2, e3, e4;
string s1; ATerm name;
/* Normal forms. */ /* Normal forms. */
if (atMatch(m, e) >> "Str" || if (atMatch(m, e) >> "Str" ||
@ -144,11 +184,12 @@ Expr evalExpr2(EvalState & state, Expr e)
return e; return e;
/* Any encountered variables must be undeclared or primops. */ /* Any encountered variables must be undeclared or primops. */
if (atMatch(m, e) >> "Var" >> s1) { if (atMatch(m, e) >> "Var" >> name) {
if (s1 == "null") return primNull(state); PrimOp0 primOp = (PrimOp0) lookupPrimOp(state.primOps0, name);
if (s1 == "true") return ATmake("Bool(True)"); if (primOp)
if (s1 == "false") return ATmake("Bool(False)"); return primOp(state);
return e; else
return e;
} }
/* Function application. */ /* Function application. */
@ -160,13 +201,9 @@ Expr evalExpr2(EvalState & state, Expr e)
e1 = evalExpr(state, e1); e1 = evalExpr(state, e1);
/* Is it a primop or a function? */ /* Is it a primop or a function? */
if (atMatch(m, e1) >> "Var" >> s1) { if (atMatch(m, e1) >> "Var" >> name) {
if (s1 == "import") return primImport(state, e2); PrimOp1 primOp = (PrimOp1) lookupPrimOp(state.primOps1, name);
if (s1 == "derivation") return primDerivation(state, e2); if (primOp) return primOp(state, e2); else abort();
if (s1 == "toString") return primToString(state, e2);
if (s1 == "baseNameOf") return primBaseNameOf(state, e2);
if (s1 == "isNull") return primIsNull(state, e2);
else throw badTerm("undefined variable/primop", e1);
} }
else if (atMatch(m, e1) >> "Function" >> formals >> e4) else if (atMatch(m, e1) >> "Function" >> formals >> e4)
@ -177,6 +214,7 @@ Expr evalExpr2(EvalState & state, Expr e)
} }
/* Attribute selection. */ /* Attribute selection. */
string s1;
if (atMatch(m, e) >> "Select" >> e1 >> s1) { if (atMatch(m, e) >> "Select" >> e1 >> s1) {
Expr a = queryAttr(evalExpr(state, e1), s1); Expr a = queryAttr(evalExpr(state, e1), s1);
if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e);
@ -261,7 +299,7 @@ Expr evalExpr(EvalState & state, Expr e)
Expr evalFile(EvalState & state, const Path & path) Expr evalFile(EvalState & state, const Path & path)
{ {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
Expr e = parseExprFromFile(path); Expr e = parseExprFromFile(state, path);
return evalExpr(state, e); return evalExpr(state, e);
} }

View file

@ -11,9 +11,17 @@
typedef map<Path, PathSet> DrvPaths; typedef map<Path, PathSet> DrvPaths;
typedef map<Path, Hash> DrvHashes; typedef map<Path, Hash> DrvHashes;
struct EvalState;
typedef Expr (* PrimOp0) (EvalState &);
typedef Expr (* PrimOp1) (EvalState &, Expr arg);
struct EvalState struct EvalState
{ {
ATermMap normalForms; ATermMap normalForms;
ATermMap primOps0; /* nullary primops */
ATermMap primOps1; /* unary primops */
ATermMap primOpsAll;
DrvPaths drvPaths; DrvPaths drvPaths;
DrvHashes drvHashes; /* normalised derivation hashes */ DrvHashes drvHashes; /* normalised derivation hashes */
Expr blackHole; Expr blackHole;
@ -22,6 +30,9 @@ struct EvalState
unsigned int nrCached; unsigned int nrCached;
EvalState(); EvalState();
void addPrimOp0(const string & name, PrimOp0 primOp);
void addPrimOp1(const string & name, PrimOp1 primOp);
}; };

View file

@ -20,8 +20,7 @@ ATermMap::ATermMap(const ATermMap & map)
table = ATtableCreate(ATgetLength(keys), maxLoadPct); table = ATtableCreate(ATgetLength(keys), maxLoadPct);
if (!table) throw Error("cannot create ATerm table"); if (!table) throw Error("cannot create ATerm table");
for (ATermIterator i(keys); i; ++i) add(map, keys);
set(*i, map.get(*i));
} }
@ -75,6 +74,26 @@ ATermList ATermMap::keys() const
} }
void ATermMap::add(const ATermMap & map)
{
ATermList keys = map.keys();
add(map, keys);
}
void ATermMap::add(const ATermMap & map, ATermList & keys)
{
for (ATermIterator i(keys); i; ++i)
set(*i, map.get(*i));
}
void ATermMap::reset()
{
ATtableReset(table);
}
ATerm string2ATerm(const string & s) ATerm string2ATerm(const string & s)
{ {
return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue)); return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue));

View file

@ -23,7 +23,7 @@ private:
ATermTable table; ATermTable table;
public: public:
ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75); ATermMap(unsigned int initialSize = 64, unsigned int maxLoadPct = 75);
ATermMap(const ATermMap & map); ATermMap(const ATermMap & map);
~ATermMap(); ~ATermMap();
@ -37,6 +37,13 @@ public:
void remove(const string & key); void remove(const string & key);
ATermList keys() const; ATermList keys() const;
void add(const ATermMap & map);
void reset();
private:
void add(const ATermMap & map, ATermList & keys);
}; };

View file

@ -66,7 +66,8 @@ int yyparse(yyscan_t scanner, ParseData * data);
} }
static Expr parse(const char * text, const string & location, static Expr parse(EvalState & state,
const char * text, const string & location,
const Path & basePath) const Path & basePath)
{ {
yyscan_t scanner; yyscan_t scanner;
@ -81,18 +82,8 @@ static Expr parse(const char * text, const string & location,
if (res) throw Error(data.error); if (res) throw Error(data.error);
ATermMap primOps;
primOps.set("import", (ATerm) ATempty);
primOps.set("derivation", (ATerm) ATempty);
primOps.set("true", (ATerm) ATempty);
primOps.set("false", (ATerm) ATempty);
primOps.set("null", (ATerm) ATempty);
primOps.set("isNull", (ATerm) ATempty);
primOps.set("toString", (ATerm) ATempty);
primOps.set("baseNameOf", (ATerm) ATempty);
try { try {
checkVarDefs(primOps, data.result); checkVarDefs(state.primOpsAll, data.result);
} catch (Error & e) { } catch (Error & e) {
throw Error(format("%1%, in %2%") % e.msg() % location); throw Error(format("%1%, in %2%") % e.msg() % location);
} }
@ -101,7 +92,7 @@ static Expr parse(const char * text, const string & location,
} }
Expr parseExprFromFile(Path path) Expr parseExprFromFile(EvalState & state, Path path)
{ {
assert(path[0] == '/'); assert(path[0] == '/');
@ -137,11 +128,12 @@ Expr parseExprFromFile(Path path)
readFull(fd, (unsigned char *) text, st.st_size); readFull(fd, (unsigned char *) text, st.st_size);
text[st.st_size] = 0; text[st.st_size] = 0;
return parse(text, "`" + path + "'", dirOf(path)); return parse(state, text, "`" + path + "'", dirOf(path));
} }
Expr parseExprFromString(const string & s, const Path & basePath) Expr parseExprFromString(EvalState & state,
const string & s, const Path & basePath)
{ {
return parse(s.c_str(), "(string)", basePath); return parse(state, s.c_str(), "(string)", basePath);
} }

View file

@ -1,15 +1,15 @@
#ifndef __PARSER_H #ifndef __PARSER_H
#define __PARSER_H #define __PARSER_H
#include "nixexpr.hh" #include "eval.hh"
/* Parse a Nix expression from the specified file. If `path' refers /* Parse a Nix expression from the specified file. If `path' refers
to a directory, the "/default.nix" is appended. */ to a directory, the "/default.nix" is appended. */
Expr parseExprFromFile(Path path); Expr parseExprFromFile(EvalState & state, Path path);
/* Parse a Nix expression from the specified string. */ /* Parse a Nix expression from the specified string. */
Expr parseExprFromString(const string & s, Expr parseExprFromString(EvalState & state, const string & s,
const Path & basePath); const Path & basePath);

View file

@ -245,6 +245,18 @@ Expr primToString(EvalState & state, Expr arg)
} }
Expr primTrue(EvalState & state)
{
return ATmake("Bool(True)");
}
Expr primFalse(EvalState & state)
{
return ATmake("Bool(False)");
}
Expr primNull(EvalState & state) Expr primNull(EvalState & state)
{ {
return ATmake("Null"); return ATmake("Null");

View file

@ -8,7 +8,7 @@
argument. */ argument. */
Expr primImport(EvalState & state, Expr arg); Expr primImport(EvalState & state, Expr arg);
/* Construct (as a unobservable) side effect) a Nix derivation /* Construct (as a unobservable side effect) a Nix derivation
expression that performs the derivation described by the argument expression that performs the derivation described by the argument
set. Returns the original set extended with the following set. Returns the original set extended with the following
attributes: `outPath' containing the primary output path of the attributes: `outPath' containing the primary output path of the
@ -24,6 +24,10 @@ Expr primBaseNameOf(EvalState & state, Expr arg);
/* Convert the argument (which can be a path or a uri) to a string. */ /* Convert the argument (which can be a path or a uri) to a string. */
Expr primToString(EvalState & state, Expr arg); Expr primToString(EvalState & state, Expr arg);
/* Boolean constructors. */
Expr primTrue(EvalState & state);
Expr primFalse(EvalState & state);
/* Return the null value. */ /* Return the null value. */
Expr primNull(EvalState & state); Expr primNull(EvalState & state);

View file

@ -4,7 +4,7 @@ nix_env_SOURCES = main.cc help.txt
nix_env_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \ nix_env_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \
../libstore/libstore.a ../libutil/libutil.a \ ../libstore/libstore.a ../libutil/libutil.a \
../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \
-lsglr -lATB -lconversion -lasfix2 -lmept -lATerm -lATerm
main.o: help.txt.hh main.o: help.txt.hh

View file

@ -102,7 +102,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs) void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs)
{ {
Expr e = parseExprFromFile(absPath(nePath)); Expr e = parseExprFromFile(state, absPath(nePath));
if (!parseDerivations(state, e, drvs)) if (!parseDerivations(state, e, drvs))
throw badTerm("expected set of derivations", e); throw badTerm("expected set of derivations", e);
} }
@ -193,7 +193,8 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
const Path & linkPath) const Path & linkPath)
{ {
/* Get the environment builder expression. */ /* Get the environment builder expression. */
Expr envBuilder = parseExprFromFile(nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */ Expr envBuilder = parseExprFromFile(state,
nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */
/* Construct the whole top level derivation. */ /* Construct the whole top level derivation. */
ATermList inputs = ATempty; ATermList inputs = ATempty;

View file

@ -4,7 +4,7 @@ nix_instantiate_SOURCES = main.cc help.txt
nix_instantiate_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \ nix_instantiate_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \
../libstore/libstore.a ../libutil/libutil.a \ ../libstore/libstore.a ../libutil/libutil.a \
../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \
-lsglr -lATB -lconversion -lasfix2 -lmept -lATerm -lATerm
main.o: help.txt.hh main.o: help.txt.hh

View file

@ -15,31 +15,12 @@ void printHelp()
} }
#if 0
static Path searchPath(const Paths & searchDirs, const Path & relPath)
{
if (string(relPath, 0, 1) == "/") return relPath;
for (Paths::const_iterator i = searchDirs.begin();
i != searchDirs.end(); i++)
{
Path path = *i + "/" + relPath;
if (pathExists(path)) return path;
}
throw Error(
format("path `%1%' not found in any of the search directories")
% relPath);
}
#endif
static Expr evalStdin(EvalState & state) static Expr evalStdin(EvalState & state)
{ {
startNest(nest, lvlTalkative, format("evaluating standard input")); startNest(nest, lvlTalkative, format("evaluating standard input"));
string s, s2; string s, s2;
while (getline(cin, s2)) s += s2 + "\n"; while (getline(cin, s2)) s += s2 + "\n";
Expr e = parseExprFromString(s, absPath(".")); Expr e = parseExprFromString(state, s, absPath("."));
return evalExpr(state, e); return evalExpr(state, e);
} }
@ -76,24 +57,11 @@ void run(Strings args)
Strings files; Strings files;
bool readStdin = false; bool readStdin = false;
#if 0
state.searchDirs.push_back(".");
state.searchDirs.push_back(nixDataDir + "/nix");
#endif
for (Strings::iterator it = args.begin(); for (Strings::iterator it = args.begin();
it != args.end(); ) it != args.end(); )
{ {
string arg = *it++; string arg = *it++;
#if 0
if (arg == "--includedir" || arg == "-I") {
if (it == args.end())
throw UsageError(format("argument required in `%1%'") % arg);
state.searchDirs.push_back(*it++);
}
else
#endif
if (arg == "-") if (arg == "-")
readStdin = true; readStdin = true;
else if (arg[0] == '-') else if (arg[0] == '-')