* Update autoCallFunction() and findAlongAttrPath().

This commit is contained in:
Eelco Dolstra 2010-04-07 15:47:06 +00:00
parent 9a64454faa
commit af2a372bb0
10 changed files with 120 additions and 188 deletions

View file

@ -6,19 +6,8 @@
namespace nix { namespace nix {
#if 0 void findAlongAttrPath(EvalState & state, const string & attrPath,
bool isAttrs(EvalState & state, Expr e, ATermMap & attrs) const Bindings & autoArgs, Expr e, Value & v)
{
e = evalExpr(state, e);
ATermList dummy;
if (!matchAttrs(e, dummy)) return false;
queryAllAttrs(e, attrs, false);
return true;
}
Expr findAlongAttrPath(EvalState & state, const string & attrPath,
const ATermMap & autoArgs, Expr e)
{ {
Strings tokens = tokenizeString(attrPath, "."); Strings tokens = tokenizeString(attrPath, ".");
@ -26,8 +15,10 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
Error(format("attribute selection path `%1%' does not match expression") % attrPath); Error(format("attribute selection path `%1%' does not match expression") % attrPath);
string curPath; string curPath;
state.mkThunk_(v, e);
for (Strings::iterator i = tokens.begin(); i != tokens.end(); ++i) { foreach (Strings::iterator, i, tokens) {
if (!curPath.empty()) curPath += "."; if (!curPath.empty()) curPath += ".";
curPath += *i; curPath += *i;
@ -39,7 +30,10 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
if (string2Int(attr, attrIndex)) apType = apIndex; if (string2Int(attr, attrIndex)) apType = apIndex;
/* Evaluate the expression. */ /* Evaluate the expression. */
e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs)); Value vTmp;
state.autoCallFunction(autoArgs, v, vTmp);
v = vTmp;
state.forceValue(v);
/* It should evaluate to either an attribute set or an /* It should evaluate to either an attribute set or an
expression, according to what is specified in the expression, according to what is specified in the
@ -47,38 +41,32 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
if (apType == apAttr) { if (apType == apAttr) {
ATermMap attrs; if (v.type != tAttrs)
if (!isAttrs(state, e, attrs))
throw TypeError( throw TypeError(
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
% curPath % showType(e)); % curPath % showType(v));
e = attrs.get(toATerm(attr));
if (!e)
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
Bindings::iterator a = v.attrs->find(toATerm(attr));
if (a == v.attrs->end())
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
v = a->second;
} }
else if (apType == apIndex) { else if (apType == apIndex) {
ATermList es; if (v.type != tList)
if (!matchList(e, es))
throw TypeError( throw TypeError(
format("the expression selected by the selection path `%1%' should be a list but is %2%") format("the expression selected by the selection path `%1%' should be a list but is %2%")
% curPath % showType(e)); % curPath % showType(v));
e = ATelementAt(es, attrIndex); if (attrIndex >= v.list.length)
if (!e) throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
throw Error(format("list index %1% in selection path `%2%' not found") % attrIndex % curPath);
v = v.list.elems[attrIndex];
} }
} }
return e;
} }
#endif
} }

View file

@ -10,8 +10,8 @@
namespace nix { namespace nix {
Expr findAlongAttrPath(EvalState & state, const string & attrPath, void findAlongAttrPath(EvalState & state, const string & attrPath,
const ATermMap & autoArgs, Expr e); const Bindings & autoArgs, Expr e, Value & v);
} }

View file

@ -9,7 +9,7 @@ namespace nix {
bool parseOptionArg(const string & arg, Strings::iterator & i, bool parseOptionArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state, const Strings::iterator & argsEnd, EvalState & state,
ATermMap & autoArgs) Bindings & autoArgs)
{ {
if (arg != "--arg" && arg != "--argstr") return false; if (arg != "--arg" && arg != "--argstr") return false;
@ -19,11 +19,13 @@ bool parseOptionArg(const string & arg, Strings::iterator & i,
string name = *i++; string name = *i++;
if (i == argsEnd) throw error; if (i == argsEnd) throw error;
string value = *i++; string value = *i++;
Expr e = arg == "--arg" Value & v(autoArgs[toATerm(name)]);
? parseExprFromString(state, value, absPath("."))
: makeStr(value); if (arg == "--arg")
autoArgs.set(toATerm(name), e); state.mkThunk_(v, parseExprFromString(state, value, absPath(".")));
else
mkString(v, value);
return true; return true;
} }

View file

@ -9,7 +9,7 @@ namespace nix {
/* Some common option parsing between nix-env and nix-instantiate. */ /* Some common option parsing between nix-env and nix-instantiate. */
bool parseOptionArg(const string & arg, Strings::iterator & i, bool parseOptionArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state, const Strings::iterator & argsEnd, EvalState & state,
ATermMap & autoArgs); Bindings & autoArgs);
} }

View file

@ -260,6 +260,12 @@ void EvalState::mkAttrs(Value & v)
} }
void EvalState::mkThunk_(Value & v, Expr expr)
{
mkThunk(v, baseEnv, expr);
}
void EvalState::cloneAttrs(Value & src, Value & dst) void EvalState::cloneAttrs(Value & src, Value & dst)
{ {
mkAttrs(dst); mkAttrs(dst);
@ -625,6 +631,37 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
} }
void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res)
{
forceValue(fun);
ATerm name;
ATermList formals;
ATermBool ellipsis;
if (fun.type != tLambda || !matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) {
res = fun;
return;
}
Value actualArgs;
mkAttrs(actualArgs);
for (ATermIterator i(formals); i; ++i) {
Expr name, def; ATerm def2;
if (!matchFormal(*i, name, def2)) abort();
Bindings::const_iterator j = args.find(name);
if (j != args.end())
(*actualArgs.attrs)[name] = j->second;
else if (!matchDefaultValue(def2, def))
throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1% ')")
% aterm2String(name));
}
callFunction(fun, actualArgs, res);
}
void EvalState::eval(Expr e, Value & v) void EvalState::eval(Expr e, Value & v)
{ {
eval(baseEnv, e, v); eval(baseEnv, e, v);
@ -1058,33 +1095,6 @@ ATermList flattenList(EvalState & state, Expr e)
} }
Expr autoCallFunction(Expr e, const ATermMap & args)
{
Pattern pat;
ATerm body, pos, name;
ATermList formals;
ATermBool ellipsis;
if (matchFunction(e, pat, body, pos) && matchAttrsPat(pat, formals, ellipsis, name)) {
ATermMap actualArgs(ATgetLength(formals));
for (ATermIterator i(formals); i; ++i) {
Expr name, def, value; ATerm def2;
if (!matchFormal(*i, name, def2)) abort();
if ((value = args.get(name)))
actualArgs.set(name, makeAttrRHS(value, makeNoPos()));
else if (!matchDefaultValue(def2, def))
throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1%')")
% aterm2String(name));
}
e = makeCall(e, makeAttrs(actualArgs));
}
return e;
}
/* Evaluation of various language constructs. These have been taken /* Evaluation of various language constructs. These have been taken
out of evalExpr2 to reduce stack space usage. (GCC is really dumb out of evalExpr2 to reduce stack space usage. (GCC is really dumb
about stack space: it just adds up all the local variables and about stack space: it just adds up all the local variables and

View file

@ -226,13 +226,18 @@ public:
void callFunction(Value & fun, Value & arg, Value & v); void callFunction(Value & fun, Value & arg, Value & v);
/* Automatically call a function for which each argument has a
default value or has a binding in the `args' map. */
void autoCallFunction(const Bindings & args, Value & fun, Value & res);
/* Allocation primitives. */ /* Allocation primitives. */
Value * allocValues(unsigned int count); Value * allocValues(unsigned int count);
Env & allocEnv(); Env & allocEnv();
void mkList(Value & v, unsigned int length); void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v); void mkAttrs(Value & v);
void mkThunk_(Value & v, Expr expr);
void cloneAttrs(Value & src, Value & dst); void cloneAttrs(Value & src, Value & dst);
/* Print statistics. */ /* Print statistics. */
@ -244,33 +249,6 @@ public:
string showType(Value & v); string showType(Value & v);
#if 0
/* Evaluate an expression to normal form. */
Expr evalExpr(EvalState & state, Expr e);
/* Evaluate an expression, and recursively evaluate list elements and
attributes. If `canonicalise' is true, we remove things like
position information and make sure that attribute sets are in
sorded order. */
Expr strictEvalExpr(EvalState & state, Expr e);
/* Specific results. */
string evalString(EvalState & state, Expr e, PathSet & context);
int evalInt(EvalState & state, Expr e);
bool evalBool(EvalState & state, Expr e);
ATermList evalList(EvalState & state, Expr e);
/* Flatten nested lists into a single list (or expand a singleton into
a list). */
ATermList flattenList(EvalState & state, Expr e);
/* Automatically call a function for which each argument has a default
value or has a binding in the `args' map. Note: result is a call,
not a normal form; it should be evaluated by calling evalExpr(). */
Expr autoCallFunction(Expr e, const ATermMap & args);
#endif
} }

View file

@ -155,11 +155,12 @@ static string addToPath(const string & s1, const string & s2)
} }
static void getDerivations(EvalState & state, Value & v, static void getDerivations(EvalState & state, Value & vIn,
const string & pathPrefix, const ATermMap & autoArgs, const string & pathPrefix, const Bindings & autoArgs,
DrvInfos & drvs, Done & done) DrvInfos & drvs, Done & done)
{ {
// !!! autoCallFunction(evalExpr(state, e), autoArgs) Value v;
state.autoCallFunction(autoArgs, vIn, v);
/* Process the expression. */ /* Process the expression. */
DrvInfo drv; DrvInfo drv;
@ -216,7 +217,7 @@ static void getDerivations(EvalState & state, Value & v,
void getDerivations(EvalState & state, Value & v, const string & pathPrefix, void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
const ATermMap & autoArgs, DrvInfos & drvs) const Bindings & autoArgs, DrvInfos & drvs)
{ {
Done done; Done done;
getDerivations(state, v, pathPrefix, autoArgs, drvs, done); getDerivations(state, v, pathPrefix, autoArgs, drvs, done);

View file

@ -65,7 +65,7 @@ typedef list<DrvInfo> DrvInfos;
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv); bool getDerivation(EvalState & state, Value & v, DrvInfo & drv);
void getDerivations(EvalState & state, Value & v, const string & pathPrefix, void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
const ATermMap & autoArgs, DrvInfos & drvs); const Bindings & autoArgs, DrvInfos & drvs);
} }

View file

@ -47,7 +47,7 @@ struct InstallSourceInfo
Path profile; /* for srcProfile */ Path profile; /* for srcProfile */
string systemFilter; /* for srcNixExprDrvs */ string systemFilter; /* for srcNixExprDrvs */
bool prebuiltOnly; bool prebuiltOnly;
ATermMap autoArgs; Bindings autoArgs;
InstallSourceInfo() : prebuiltOnly(false) { }; InstallSourceInfo() : prebuiltOnly(false) { };
}; };
@ -161,13 +161,11 @@ static Expr loadSourceExpr(EvalState & state, const Path & path)
static void loadDerivations(EvalState & state, Path nixExprPath, static void loadDerivations(EvalState & state, Path nixExprPath,
string systemFilter, const ATermMap & autoArgs, string systemFilter, const Bindings & autoArgs,
const string & pathPrefix, DrvInfos & elems) const string & pathPrefix, DrvInfos & elems)
{ {
Value v; Value v;
state.eval(loadSourceExpr(state, nixExprPath), v); findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath), v);
// !!! findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath))
getDerivations(state, v, pathPrefix, autoArgs, elems); getDerivations(state, v, pathPrefix, autoArgs, elems);
@ -579,14 +577,12 @@ static void queryInstSources(EvalState & state,
} }
case srcAttrPath: { case srcAttrPath: {
throw Error("not implemented"); foreach (Strings::const_iterator, i, args) {
#if 0 Value v;
foreach (Strings::const_iterator, i, args) findAlongAttrPath(state, *i, instSource.autoArgs,
getDerivations(state, loadSourceExpr(state, instSource.nixExprPath), v);
findAlongAttrPath(state, *i, instSource.autoArgs, getDerivations(state, v, "", instSource.autoArgs, elems);
loadSourceExpr(state, instSource.nixExprPath)), }
"", instSource.autoArgs, elems);
#endif
break; break;
} }
} }

View file

@ -37,80 +37,41 @@ static int rootNr = 0;
static bool indirectRoot = false; static bool indirectRoot = false;
#if 0
static void printResult(EvalState & state, Expr e,
bool evalOnly, bool xmlOutput, const ATermMap & autoArgs)
{
PathSet context;
if (evalOnly)
if (xmlOutput)
printTermAsXML(e, std::cout, context);
else
std::cout << format("%1%\n") % canonicaliseExpr(e);
else {
DrvInfos drvs;
getDerivations(state, e, "", autoArgs, drvs);
for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i) {
Path drvPath = i->queryDrvPath(state);
if (gcRoot == "")
printGCWarning();
else
drvPath = addPermRoot(drvPath,
makeRootName(gcRoot, rootNr),
indirectRoot);
std::cout << format("%1%\n") % drvPath;
}
}
}
#endif
void processExpr(EvalState & state, const Strings & attrPaths, void processExpr(EvalState & state, const Strings & attrPaths,
bool parseOnly, bool strict, const ATermMap & autoArgs, bool parseOnly, bool strict, const Bindings & autoArgs,
bool evalOnly, bool xmlOutput, Expr e) bool evalOnly, bool xmlOutput, Expr e)
{ {
if (parseOnly) if (parseOnly)
std::cout << format("%1%\n") % canonicaliseExpr(e); std::cout << format("%1%\n") % canonicaliseExpr(e);
else { else
Value v; foreach (Strings::const_iterator, i, attrPaths) {
PathSet context; Value v;
state.eval(e, v); findAlongAttrPath(state, *i, autoArgs, e, v);
if (evalOnly) state.forceValue(v);
if (xmlOutput)
printValueAsXML(state, strict, v, std::cout, context); PathSet context;
if (evalOnly)
if (xmlOutput)
printValueAsXML(state, strict, v, std::cout, context);
else {
if (strict) state.strictForceValue(v);
std::cout << v << std::endl;
}
else { else {
if (strict) state.strictForceValue(v); DrvInfos drvs;
std::cout << v << std::endl; getDerivations(state, v, "", autoArgs, drvs);
} foreach (DrvInfos::iterator, i, drvs) {
else { Path drvPath = i->queryDrvPath(state);
DrvInfos drvs; if (gcRoot == "")
getDerivations(state, v, "", autoArgs, drvs); printGCWarning();
foreach (DrvInfos::iterator, i, drvs) { else
Path drvPath = i->queryDrvPath(state); drvPath = addPermRoot(drvPath,
if (gcRoot == "") makeRootName(gcRoot, rootNr),
printGCWarning(); indirectRoot);
else std::cout << format("%1%\n") % drvPath;
drvPath = addPermRoot(drvPath, }
makeRootName(gcRoot, rootNr),
indirectRoot);
std::cout << format("%1%\n") % drvPath;
} }
} }
}
#if 0
for (Strings::const_iterator i = attrPaths.begin(); i != attrPaths.end(); ++i) {
Expr e2 = findAlongAttrPath(state, *i, autoArgs, e);
if (!parseOnly)
if (strict)
e2 = state.strictEval(e2);
else
e2 = evalExpr(state, e2);
printResult(state, e2, evalOnly, xmlOutput, autoArgs);
}
#endif
} }
@ -124,11 +85,9 @@ void run(Strings args)
bool xmlOutput = false; bool xmlOutput = false;
bool strict = false; bool strict = false;
Strings attrPaths; Strings attrPaths;
ATermMap autoArgs(128); Bindings autoArgs;
for (Strings::iterator i = args.begin(); for (Strings::iterator i = args.begin(); i != args.end(); ) {
i != args.end(); )
{
string arg = *i++; string arg = *i++;
if (arg == "-") if (arg == "-")
@ -175,9 +134,7 @@ void run(Strings args)
evalOnly, xmlOutput, e); evalOnly, xmlOutput, e);
} }
for (Strings::iterator i = files.begin(); foreach (Strings::iterator, i, files) {
i != files.end(); i++)
{
Path path = absPath(*i); Path path = absPath(*i);
Expr e = parseExprFromFile(state, path); Expr e = parseExprFromFile(state, path);
processExpr(state, attrPaths, parseOnly, strict, autoArgs, processExpr(state, attrPaths, parseOnly, strict, autoArgs,