* More primops.

This commit is contained in:
Eelco Dolstra 2010-03-30 22:39:48 +00:00
parent 47df476daa
commit 7f19e03c65
3 changed files with 109 additions and 91 deletions

View file

@ -254,6 +254,13 @@ void EvalState::mkList(Value & v, unsigned int length)
} }
void EvalState::mkAttrs(Value & v)
{
v.type = tAttrs;
v.attrs = new Bindings;
}
void EvalState::evalFile(const Path & path, Value & v) void EvalState::evalFile(const Path & path, Value & v)
{ {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
@ -308,8 +315,7 @@ void EvalState::eval(Env & env, Expr e, Value & v)
mkPath(v, ATgetName(ATgetAFun(s))); mkPath(v, ATgetName(ATgetAFun(s)));
else if (matchAttrs(e, es)) { else if (matchAttrs(e, es)) {
v.type = tAttrs; mkAttrs(v);
v.attrs = new Bindings;
ATerm e2, pos; ATerm e2, pos;
for (ATermIterator i(es); i; ++i) { for (ATermIterator i(es); i; ++i) {
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
@ -468,8 +474,7 @@ void EvalState::eval(Env & env, Expr e, Value & v)
/* Attribute set update (//). */ /* Attribute set update (//). */
else if (matchOpUpdate(e, e1, e2)) { else if (matchOpUpdate(e, e1, e2)) {
v.type = tAttrs; mkAttrs(v);
v.attrs = new Bindings;
Value v2; Value v2;
eval(env, e2, v2); eval(env, e2, v2);

View file

@ -105,7 +105,7 @@ static inline void mkBool(Value & v, bool b)
void mkString(Value & v, const char * s); void mkString(Value & v, const char * s);
void mkString(Value & v, const string & s, const PathSet & context); void mkString(Value & v, const string & s, const PathSet & context = PathSet());
void mkPath(Value & v, const char * s); void mkPath(Value & v, const char * s);
@ -207,6 +207,7 @@ public:
Env & allocEnv(); Env & allocEnv();
void mkList(Value & v, unsigned int length); void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v);
/* Print statistics. */ /* Print statistics. */
void printStats(); void printStats();

View file

@ -45,45 +45,47 @@ static void prim_import(EvalState & state, Value * * args, Value & v)
} }
#if 0
/* Determine whether the argument is the null value. */ /* Determine whether the argument is the null value. */
static void prim_isNull(EvalState & state, Value * * args, Value & v) static void prim_isNull(EvalState & state, Value * * args, Value & v)
{ {
return makeBool(matchNull(evalExpr(state, args[0]))); state.forceValue(*args[0]);
mkBool(v, args[0]->type == tNull);
} }
/* Determine whether the argument is a function. */ /* Determine whether the argument is a function. */
static void prim_isFunction(EvalState & state, Value * * args, Value & v) static void prim_isFunction(EvalState & state, Value * * args, Value & v)
{ {
Expr e = evalExpr(state, args[0]); state.forceValue(*args[0]);
Pattern pat; mkBool(v, args[0]->type == tLambda);
ATerm body, pos;
return makeBool(matchFunction(e, pat, body, pos));
} }
/* Determine whether the argument is an Int. */ /* Determine whether the argument is an Int. */
static void prim_isInt(EvalState & state, Value * * args, Value & v) static void prim_isInt(EvalState & state, Value * * args, Value & v)
{ {
int i; state.forceValue(*args[0]);
return makeBool(matchInt(evalExpr(state, args[0]), i)); mkBool(v, args[0]->type == tInt);
} }
/* Determine whether the argument is an String. */ /* Determine whether the argument is an String. */
static void prim_isString(EvalState & state, Value * * args, Value & v) static void prim_isString(EvalState & state, Value * * args, Value & v)
{ {
string s; state.forceValue(*args[0]);
PathSet l; mkBool(v, args[0]->type == tString);
return makeBool(matchStr(evalExpr(state, args[0]), s, l));
} }
/* Determine whether the argument is an Bool. */ /* Determine whether the argument is an Bool. */
static void prim_isBool(EvalState & state, Value * * args, Value & v) static void prim_isBool(EvalState & state, Value * * args, Value & v)
{ {
ATermBool b; state.forceValue(*args[0]);
return makeBool(matchBool(evalExpr(state, args[0]), b)); mkBool(v, args[0]->type == tBool);
} }
#if 0
static void prim_genericClosure(EvalState & state, Value * * args, Value & v) static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
{ {
startNest(nest, lvlDebug, "finding dependencies"); startNest(nest, lvlDebug, "finding dependencies");
@ -130,13 +132,14 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
return makeList(res); return makeList(res);
} }
#endif
static void prim_abort(EvalState & state, Value * * args, Value & v) static void prim_abort(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
throw Abort(format("evaluation aborted with the following error message: `%1%'") % throw Abort(format("evaluation aborted with the following error message: `%1%'") %
evalString(state, args[0], context)); state.coerceToString(*args[0], context));
} }
@ -144,10 +147,11 @@ static void prim_throw(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
throw ThrownError(format("user-thrown exception: %1%") % throw ThrownError(format("user-thrown exception: %1%") %
evalString(state, args[0], context)); state.coerceToString(*args[0], context));
} }
#if 0
static void prim_addErrorContext(EvalState & state, Value * * args, Value & v) static void prim_addErrorContext(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
@ -176,16 +180,18 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v)
} }
return makeAttrs(res); return makeAttrs(res);
} }
#endif
/* Return an environment variable. Use with care. */ /* Return an environment variable. Use with care. */
static void prim_getEnv(EvalState & state, Value * * args, Value & v) static void prim_getEnv(EvalState & state, Value * * args, Value & v)
{ {
string name = evalStringNoCtx(state, args[0]); string name = state.forceStringNoCtx(*args[0]);
return makeStr(getEnv(name)); mkString(v, getEnv(name));
} }
#if 0
/* Evaluate the first expression, and print its abstract syntax tree /* Evaluate the first expression, and print its abstract syntax tree
on standard error. Then return the second expression. Useful for on standard error. Then return the second expression. Useful for
debugging. debugging.
@ -488,6 +494,7 @@ static void prim_derivationLazy(EvalState & state, Value * * args, Value & v)
return makeAttrs(attrs); return makeAttrs(attrs);
} }
#endif
/************************************************************* /*************************************************************
@ -499,11 +506,12 @@ static void prim_derivationLazy(EvalState & state, Value * * args, Value & v)
static void prim_toPath(EvalState & state, Value * * args, Value & v) static void prim_toPath(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
string path = coerceToPath(state, args[0], context); string path = state.coerceToPath(*args[0], context);
return makeStr(canonPath(path), context); mkString(v, canonPath(path), context);
} }
#if 0
/* Allow a valid store path to be used in an expression. This is /* Allow a valid store path to be used in an expression. This is
useful in some generated expressions such as in nix-push, which useful in some generated expressions such as in nix-push, which
generates a call to a function with an already existing store path generates a call to a function with an already existing store path
@ -524,15 +532,16 @@ static void prim_storePath(EvalState & state, Value * * args, Value & v)
context.insert(path2); context.insert(path2);
return makeStr(path, context); return makeStr(path, context);
} }
#endif
static void prim_pathExists(EvalState & state, Value * * args, Value & v) static void prim_pathExists(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
Path path = coerceToPath(state, args[0], context); Path path = state.coerceToPath(*args[0], context);
if (!context.empty()) if (!context.empty())
throw EvalError(format("string `%1%' cannot refer to other paths") % path); throw EvalError(format("string `%1%' cannot refer to other paths") % path);
return makeBool(pathExists(path)); mkBool(v, pathExists(path));
} }
@ -541,7 +550,7 @@ static void prim_pathExists(EvalState & state, Value * * args, Value & v)
static void prim_baseNameOf(EvalState & state, Value * * args, Value & v) static void prim_baseNameOf(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
return makeStr(baseNameOf(coerceToString(state, args[0], context)), context); mkString(v, baseNameOf(state.coerceToString(*args[0], context)), context);
} }
@ -551,10 +560,8 @@ static void prim_baseNameOf(EvalState & state, Value * * args, Value & v)
static void prim_dirOf(EvalState & state, Value * * args, Value & v) static void prim_dirOf(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
Expr e = evalExpr(state, args[0]); ATerm dummy; Path dir = dirOf(state.coerceToPath(*args[0], context));
bool isPath = matchPath(e, dummy); if (args[0]->type == tPath) mkPath(v, dir.c_str()); else mkString(v, dir, context);
Path dir = dirOf(coerceToPath(state, e, context));
return isPath ? makePath(toATerm(dir)) : makeStr(dir, context);
} }
@ -562,10 +569,10 @@ static void prim_dirOf(EvalState & state, Value * * args, Value & v)
static void prim_readFile(EvalState & state, Value * * args, Value & v) static void prim_readFile(EvalState & state, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
Path path = coerceToPath(state, args[0], context); Path path = state.coerceToPath(*args[0], context);
if (!context.empty()) if (!context.empty())
throw EvalError(format("string `%1%' cannot refer to other paths") % path); throw EvalError(format("string `%1%' cannot refer to other paths") % path);
return makeStr(readFile(path)); mkString(v, readFile(path).c_str());
} }
@ -574,6 +581,7 @@ static void prim_readFile(EvalState & state, Value * * args, Value & v)
*************************************************************/ *************************************************************/
#if 0
/* Convert the argument (which can be any Nix expression) to an XML /* Convert the argument (which can be any Nix expression) to an XML
representation returned in a string. Not all Nix expressions can representation returned in a string. Not all Nix expressions can
be sensibly or completely represented (e.g., functions). */ be sensibly or completely represented (e.g., functions). */
@ -662,6 +670,7 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v)
return makeStr(dstPath, singleton<PathSet>(dstPath)); return makeStr(dstPath, singleton<PathSet>(dstPath));
} }
#endif
/************************************************************* /*************************************************************
@ -673,21 +682,18 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v)
list of strings. */ list of strings. */
static void prim_attrNames(EvalState & state, Value * * args, Value & v) static void prim_attrNames(EvalState & state, Value * * args, Value & v)
{ {
ATermMap attrs; state.forceAttrs(*args[0]);
queryAllAttrs(evalExpr(state, args[0]), attrs);
state.mkList(v, args[0]->attrs->size());
StringSet names; StringSet names;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) foreach (Bindings::iterator, i, *args[0]->attrs)
names.insert(aterm2String(i->key)); names.insert(aterm2String(i->first));
ATermList list = ATempty; unsigned int n = 0;
for (StringSet::const_reverse_iterator i = names.rbegin(); foreach (StringSet::iterator, i, names)
i != names.rend(); ++i) mkString(v.list.elems[n++], *i);
list = ATinsert(list, makeStr(*i, PathSet()));
return makeList(list);
} }
#endif
/* Dynamic version of the `.' operator. */ /* Dynamic version of the `.' operator. */
@ -712,6 +718,31 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
} }
/* Determine whether the argument is an attribute set. */
static void prim_isAttrs(EvalState & state, Value * * args, Value & v)
{
state.forceValue(*args[0]);
mkBool(v, args[0]->type == tAttrs);
}
static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
{
state.forceAttrs(*args[0]);
state.forceList(*args[1]);
state.mkAttrs(v);
foreach (Bindings::iterator, i, *args[0]->attrs)
(*v.attrs)[i->first] = i->second;
for (unsigned int i = 0; i < args[1]->list.length; ++i) {
state.forceStringNoCtx(args[1]->list.elems[i]);
v.attrs->erase(toATerm(args[1]->list.elems[i].string.s));
}
}
#if 0 #if 0
/* Builds an attribute set from a list specifying (name, value) /* Builds an attribute set from a list specifying (name, value)
pairs. To be precise, a list [{name = "name1"; value = value1;} pairs. To be precise, a list [{name = "name1"; value = value1;}
@ -745,31 +776,10 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
throw; throw;
} }
} }
#endif
static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) #if 0
{
ATermMap attrs;
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
ATermList list = evalList(state, args[1]);
for (ATermIterator i(list); i; ++i)
/* It's not an error for *i not to exist. */
attrs.remove(toATerm(evalStringNoCtx(state, *i)));
return makeAttrs(attrs);
}
/* Determine whether the argument is an attribute set. */
static void prim_isAttrs(EvalState & state, Value * * args, Value & v)
{
ATermList list;
return makeBool(matchAttrs(evalExpr(state, args[0]), list));
}
/* Return the right-biased intersection of two attribute sets as1 and /* Return the right-biased intersection of two attribute sets as1 and
as2, i.e. a set that contains every attribute from as2 that is also as2, i.e. a set that contains every attribute from as2 that is also
a member of as1. */ a member of as1. */
@ -827,6 +837,7 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v)
return makeAttrs(as); return makeAttrs(as);
} }
#endif
/************************************************************* /*************************************************************
@ -837,10 +848,9 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v)
/* Determine whether the argument is a list. */ /* Determine whether the argument is a list. */
static void prim_isList(EvalState & state, Value * * args, Value & v) static void prim_isList(EvalState & state, Value * * args, Value & v)
{ {
ATermList list; state.forceValue(*args[0]);
return makeBool(matchList(evalExpr(state, args[0]), list)); mkBool(v, args[0]->type == tList);
} }
#endif
/* Return the first element of a list. */ /* Return the first element of a list. */
@ -883,14 +893,12 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
} }
#if 0
/* Return the length of a list. This is an O(1) time operation. */ /* Return the length of a list. This is an O(1) time operation. */
static void prim_length(EvalState & state, Value * * args, Value & v) static void prim_length(EvalState & state, Value * * args, Value & v)
{ {
ATermList list = evalList(state, args[0]); state.forceList(*args[0]);
return makeInt(ATgetLength(list)); mkInt(v, v.list.length);
} }
#endif
/************************************************************* /*************************************************************
@ -1022,6 +1030,7 @@ static void prim_stringToExpr(EvalState & state, Value * * args, Value & v)
throw EvalError("stringToExpr needs string argument!"); throw EvalError("stringToExpr needs string argument!");
return ATreadFromString(s.c_str()); return ATreadFromString(s.c_str());
} }
#endif
/************************************************************* /*************************************************************
@ -1031,23 +1040,20 @@ static void prim_stringToExpr(EvalState & state, Value * * args, Value & v)
static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) static void prim_parseDrvName(EvalState & state, Value * * args, Value & v)
{ {
string name = evalStringNoCtx(state, args[0]); string name = state.forceStringNoCtx(*args[0]);
DrvName parsed(name); DrvName parsed(name);
ATermMap attrs(2); state.mkAttrs(v);
attrs.set(toATerm("name"), makeAttrRHS(makeStr(parsed.name), makeNoPos())); mkString((*v.attrs)[toATerm("name")], parsed.name);
attrs.set(toATerm("version"), makeAttrRHS(makeStr(parsed.version), makeNoPos())); mkString((*v.attrs)[toATerm("version")], parsed.version);
return makeAttrs(attrs);
} }
static void prim_compareVersions(EvalState & state, Value * * args, Value & v) static void prim_compareVersions(EvalState & state, Value * * args, Value & v)
{ {
string version1 = evalStringNoCtx(state, args[0]); string version1 = state.forceStringNoCtx(*args[0]);
string version2 = evalStringNoCtx(state, args[1]); string version2 = state.forceStringNoCtx(*args[1]);
int d = compareVersions(version1, version2); mkInt(v, compareVersions(version1, version2));
return makeInt(d);
} }
#endif
/************************************************************* /*************************************************************
@ -1084,18 +1090,22 @@ void EvalState::createBaseEnv()
// Miscellaneous // Miscellaneous
addPrimOp("import", 1, prim_import); addPrimOp("import", 1, prim_import);
#if 0
addPrimOp("isNull", 1, prim_isNull); addPrimOp("isNull", 1, prim_isNull);
addPrimOp("__isFunction", 1, prim_isFunction); addPrimOp("__isFunction", 1, prim_isFunction);
addPrimOp("__isString", 1, prim_isString); addPrimOp("__isString", 1, prim_isString);
addPrimOp("__isInt", 1, prim_isInt); addPrimOp("__isInt", 1, prim_isInt);
addPrimOp("__isBool", 1, prim_isBool); addPrimOp("__isBool", 1, prim_isBool);
#if 0
addPrimOp("__genericClosure", 1, prim_genericClosure); addPrimOp("__genericClosure", 1, prim_genericClosure);
#endif
addPrimOp("abort", 1, prim_abort); addPrimOp("abort", 1, prim_abort);
addPrimOp("throw", 1, prim_throw); addPrimOp("throw", 1, prim_throw);
#if 0
addPrimOp("__addErrorContext", 2, prim_addErrorContext); addPrimOp("__addErrorContext", 2, prim_addErrorContext);
addPrimOp("__tryEval", 1, prim_tryEval); addPrimOp("__tryEval", 1, prim_tryEval);
#endif
addPrimOp("__getEnv", 1, prim_getEnv); addPrimOp("__getEnv", 1, prim_getEnv);
#if 0
addPrimOp("__trace", 2, prim_trace); addPrimOp("__trace", 2, prim_trace);
// Expr <-> String // Expr <-> String
@ -1105,41 +1115,43 @@ void EvalState::createBaseEnv()
// Derivations // Derivations
addPrimOp("derivation!", 1, prim_derivationStrict); addPrimOp("derivation!", 1, prim_derivationStrict);
addPrimOp("derivation", 1, prim_derivationLazy); addPrimOp("derivation", 1, prim_derivationLazy);
#endif
// Paths // Paths
addPrimOp("__toPath", 1, prim_toPath); addPrimOp("__toPath", 1, prim_toPath);
#if 0
addPrimOp("__storePath", 1, prim_storePath); addPrimOp("__storePath", 1, prim_storePath);
#endif
addPrimOp("__pathExists", 1, prim_pathExists); addPrimOp("__pathExists", 1, prim_pathExists);
addPrimOp("baseNameOf", 1, prim_baseNameOf); addPrimOp("baseNameOf", 1, prim_baseNameOf);
addPrimOp("dirOf", 1, prim_dirOf); addPrimOp("dirOf", 1, prim_dirOf);
addPrimOp("__readFile", 1, prim_readFile); addPrimOp("__readFile", 1, prim_readFile);
// Creating files // Creating files
#if 0
addPrimOp("__toXML", 1, prim_toXML); addPrimOp("__toXML", 1, prim_toXML);
addPrimOp("__toFile", 2, prim_toFile); addPrimOp("__toFile", 2, prim_toFile);
addPrimOp("__filterSource", 2, prim_filterSource); addPrimOp("__filterSource", 2, prim_filterSource);
#endif
// Attribute sets // Attribute sets
addPrimOp("__attrNames", 1, prim_attrNames); addPrimOp("__attrNames", 1, prim_attrNames);
#endif
addPrimOp("__getAttr", 2, prim_getAttr); addPrimOp("__getAttr", 2, prim_getAttr);
addPrimOp("__hasAttr", 2, prim_hasAttr); addPrimOp("__hasAttr", 2, prim_hasAttr);
#if 0
addPrimOp("__isAttrs", 1, prim_isAttrs); addPrimOp("__isAttrs", 1, prim_isAttrs);
addPrimOp("removeAttrs", 2, prim_removeAttrs); addPrimOp("removeAttrs", 2, prim_removeAttrs);
#if 0
addPrimOp("__listToAttrs", 1, prim_listToAttrs); addPrimOp("__listToAttrs", 1, prim_listToAttrs);
addPrimOp("__intersectAttrs", 2, prim_intersectAttrs); addPrimOp("__intersectAttrs", 2, prim_intersectAttrs);
addPrimOp("__functionArgs", 1, prim_functionArgs); addPrimOp("__functionArgs", 1, prim_functionArgs);
#endif
// Lists // Lists
addPrimOp("__isList", 1, prim_isList); addPrimOp("__isList", 1, prim_isList);
#endif
addPrimOp("__head", 1, prim_head); addPrimOp("__head", 1, prim_head);
addPrimOp("__tail", 1, prim_tail); addPrimOp("__tail", 1, prim_tail);
addPrimOp("map", 2, prim_map); addPrimOp("map", 2, prim_map);
#if 0
addPrimOp("__length", 1, prim_length); addPrimOp("__length", 1, prim_length);
#endif
// Integer arithmetic // Integer arithmetic
addPrimOp("__add", 2, prim_add); addPrimOp("__add", 2, prim_add);
@ -1155,11 +1167,11 @@ void EvalState::createBaseEnv()
#if 0 #if 0
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
#endif
// Versions // Versions
addPrimOp("__parseDrvName", 1, prim_parseDrvName); addPrimOp("__parseDrvName", 1, prim_parseDrvName);
addPrimOp("__compareVersions", 2, prim_compareVersions); addPrimOp("__compareVersions", 2, prim_compareVersions);
#endif
} }