* More operators / primops.
This commit is contained in:
parent
c9170be2bd
commit
47df476daa
5 changed files with 145 additions and 187 deletions
|
@ -72,6 +72,7 @@ void run(Strings args)
|
||||||
//doTest("import ./foo.nix");
|
//doTest("import ./foo.nix");
|
||||||
doTest("map (x: __add 1 x) [ 1 2 3 ]");
|
doTest("map (x: __add 1 x) [ 1 2 3 ]");
|
||||||
doTest("map (builtins.add 1) [ 1 2 3 ]");
|
doTest("map (builtins.add 1) [ 1 2 3 ]");
|
||||||
|
doTest("builtins.hasAttr \"x\" { x = 1; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,28 @@ static void mkThunk(Value & v, Env & env, Expr expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mkString(Value & v, const char * s)
|
||||||
|
{
|
||||||
|
v.type = tString;
|
||||||
|
v.string.s = strdup(s);
|
||||||
|
v.string.context = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mkString(Value & v, const string & s, const PathSet & context)
|
||||||
|
{
|
||||||
|
mkString(v, s.c_str());
|
||||||
|
// !!! context
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mkPath(Value & v, const char * s)
|
||||||
|
{
|
||||||
|
v.type = tPath;
|
||||||
|
v.path = strdup(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Value * lookupWith(Env * env, Sym name)
|
static Value * lookupWith(Env * env, Sym name)
|
||||||
{
|
{
|
||||||
if (!env) return 0;
|
if (!env) return 0;
|
||||||
|
@ -206,7 +228,7 @@ static Value * lookupVar(Env * env, Sym name)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
throw Error("undefined variable");
|
throw Error(format("undefined variable `%1%'") % aterm2String(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -257,38 +279,35 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
char x;
|
char x;
|
||||||
if (&x < deepestStack) deepestStack = &x;
|
if (&x < deepestStack) deepestStack = &x;
|
||||||
|
|
||||||
printMsg(lvlError, format("eval: %1%") % e);
|
debug(format("eval: %1%") % e);
|
||||||
|
|
||||||
nrEvaluated++;
|
nrEvaluated++;
|
||||||
|
|
||||||
Sym name;
|
Sym name;
|
||||||
|
int n;
|
||||||
|
ATerm s; ATermList context, es;
|
||||||
|
ATermList rbnds, nrbnds;
|
||||||
|
Expr e1, e2, e3, fun, arg, attrs;
|
||||||
|
Pattern pat; Expr body; Pos pos;
|
||||||
|
|
||||||
if (matchVar(e, name)) {
|
if (matchVar(e, name)) {
|
||||||
Value * v2 = lookupVar(&env, name);
|
Value * v2 = lookupVar(&env, name);
|
||||||
forceValue(*v2);
|
forceValue(*v2);
|
||||||
v = *v2;
|
v = *v2;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int n;
|
else if (matchInt(e, n))
|
||||||
if (matchInt(e, n)) {
|
|
||||||
mkInt(v, n);
|
mkInt(v, n);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ATerm s; ATermList context;
|
else if (matchStr(e, s, context)) {
|
||||||
if (matchStr(e, s, context)) {
|
|
||||||
assert(context == ATempty);
|
assert(context == ATempty);
|
||||||
mkString(v, strdup(ATgetName(ATgetAFun(s))));
|
mkString(v, ATgetName(ATgetAFun(s)));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchPath(e, s)) {
|
else if (matchPath(e, s))
|
||||||
mkPath(v, strdup(ATgetName(ATgetAFun(s))));
|
mkPath(v, ATgetName(ATgetAFun(s)));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ATermList es;
|
else if (matchAttrs(e, es)) {
|
||||||
if (matchAttrs(e, es)) {
|
|
||||||
v.type = tAttrs;
|
v.type = tAttrs;
|
||||||
v.attrs = new Bindings;
|
v.attrs = new Bindings;
|
||||||
ATerm e2, pos;
|
ATerm e2, pos;
|
||||||
|
@ -298,11 +317,9 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
nrValues++;
|
nrValues++;
|
||||||
mkThunk(v2, env, e2);
|
mkThunk(v2, env, e2);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ATermList rbnds, nrbnds;
|
else if (matchRec(e, rbnds, nrbnds)) {
|
||||||
if (matchRec(e, rbnds, nrbnds)) {
|
|
||||||
Env & env2(allocEnv());
|
Env & env2(allocEnv());
|
||||||
env2.up = &env;
|
env2.up = &env;
|
||||||
|
|
||||||
|
@ -315,12 +332,9 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
nrValues++;
|
nrValues++;
|
||||||
mkThunk(v2, env2, e2);
|
mkThunk(v2, env2, e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr e1, e2;
|
else if (matchSelect(e, e2, name)) {
|
||||||
if (matchSelect(e, e2, name)) {
|
|
||||||
eval(env, e2, v);
|
eval(env, e2, v);
|
||||||
forceAttrs(v); // !!! eval followed by force is slightly inefficient
|
forceAttrs(v); // !!! eval followed by force is slightly inefficient
|
||||||
Bindings::iterator i = v.attrs->find(name);
|
Bindings::iterator i = v.attrs->find(name);
|
||||||
|
@ -333,29 +347,23 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
v = i->second;
|
v = i->second;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern pat; Expr body; Pos pos;
|
else if (matchFunction(e, pat, body, pos)) {
|
||||||
if (matchFunction(e, pat, body, pos)) {
|
|
||||||
v.type = tLambda;
|
v.type = tLambda;
|
||||||
v.lambda.env = &env;
|
v.lambda.env = &env;
|
||||||
v.lambda.pat = pat;
|
v.lambda.pat = pat;
|
||||||
v.lambda.body = body;
|
v.lambda.body = body;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr fun, arg;
|
else if (matchCall(e, fun, arg)) {
|
||||||
if (matchCall(e, fun, arg)) {
|
|
||||||
eval(env, fun, v);
|
eval(env, fun, v);
|
||||||
Value vArg;
|
Value vArg;
|
||||||
mkThunk(vArg, env, arg); // !!! should this be on the heap?
|
mkThunk(vArg, env, arg); // !!! should this be on the heap?
|
||||||
callFunction(v, vArg, v);
|
callFunction(v, vArg, v);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr attrs;
|
else if (matchWith(e, attrs, body, pos)) {
|
||||||
if (matchWith(e, attrs, body, pos)) {
|
|
||||||
Env & env2(allocEnv());
|
Env & env2(allocEnv());
|
||||||
env2.up = &env;
|
env2.up = &env;
|
||||||
|
|
||||||
|
@ -365,31 +373,27 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
forceAttrs(vAttrs);
|
forceAttrs(vAttrs);
|
||||||
|
|
||||||
eval(env2, body, v);
|
eval(env2, body, v);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchList(e, es)) {
|
else if (matchList(e, es)) {
|
||||||
mkList(v, ATgetLength(es));
|
mkList(v, ATgetLength(es));
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es))
|
for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es))
|
||||||
mkThunk(v.list.elems[n], env, ATgetFirst(es));
|
mkThunk(v.list.elems[n], env, ATgetFirst(es));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchOpEq(e, e1, e2)) {
|
else if (matchOpEq(e, e1, e2)) {
|
||||||
Value v1; eval(env, e1, v1);
|
Value v1; eval(env, e1, v1);
|
||||||
Value v2; eval(env, e2, v2);
|
Value v2; eval(env, e2, v2);
|
||||||
mkBool(v, eqValues(v1, v2));
|
mkBool(v, eqValues(v1, v2));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchOpNEq(e, e1, e2)) {
|
else if (matchOpNEq(e, e1, e2)) {
|
||||||
Value v1; eval(env, e1, v1);
|
Value v1; eval(env, e1, v1);
|
||||||
Value v2; eval(env, e2, v2);
|
Value v2; eval(env, e2, v2);
|
||||||
mkBool(v, !eqValues(v1, v2));
|
mkBool(v, !eqValues(v1, v2));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchOpConcat(e, e1, e2)) {
|
else if (matchOpConcat(e, e1, e2)) {
|
||||||
Value v1; eval(env, e1, v1);
|
Value v1; eval(env, e1, v1);
|
||||||
forceList(v1);
|
forceList(v1);
|
||||||
Value v2; eval(env, e2, v2);
|
Value v2; eval(env, e2, v2);
|
||||||
|
@ -401,10 +405,9 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
v.list.elems[n] = v1.list.elems[n];
|
v.list.elems[n] = v1.list.elems[n];
|
||||||
for (unsigned int n = 0; n < v2.list.length; ++n)
|
for (unsigned int n = 0; n < v2.list.length; ++n)
|
||||||
v.list.elems[n + v1.list.length] = v2.list.elems[n];
|
v.list.elems[n + v1.list.length] = v2.list.elems[n];
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchConcatStrings(e, es)) {
|
else if (matchConcatStrings(e, es)) {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
|
|
||||||
|
@ -431,24 +434,62 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
% s.str());
|
% s.str());
|
||||||
|
|
||||||
if (isPath)
|
if (isPath)
|
||||||
mkPath(v, strdup(s.str().c_str()));
|
mkPath(v, s.str().c_str());
|
||||||
else
|
else
|
||||||
mkString(v, strdup(s.str().c_str())); // !!! context
|
mkString(v, s.str().c_str()); // !!! context
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr e3;
|
/* Conditionals. */
|
||||||
if (matchIf(e, e1, e2, e3)) {
|
else if (matchIf(e, e1, e2, e3))
|
||||||
eval(env, evalBool(env, e1) ? e2 : e3, v);
|
eval(env, evalBool(env, e1) ? e2 : e3, v);
|
||||||
return;
|
|
||||||
|
/* Assertions. */
|
||||||
|
else if (matchAssert(e, e1, e2, pos)) {
|
||||||
|
if (!evalBool(env, e1))
|
||||||
|
throw AssertionError(format("assertion failed at %1%") % showPos(pos));
|
||||||
|
eval(env, e2, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchOpOr(e, e1, e2)) {
|
/* Negation. */
|
||||||
|
else if (matchOpNot(e, e1))
|
||||||
|
mkBool(v, !evalBool(env, e1));
|
||||||
|
|
||||||
|
/* Implication. */
|
||||||
|
else if (matchOpImpl(e, e1, e2))
|
||||||
|
return mkBool(v, !evalBool(env, e1) || evalBool(env, e2));
|
||||||
|
|
||||||
|
/* Conjunction (logical AND). */
|
||||||
|
else if (matchOpAnd(e, e1, e2))
|
||||||
|
mkBool(v, evalBool(env, e1) && evalBool(env, e2));
|
||||||
|
|
||||||
|
/* Disjunction (logical OR). */
|
||||||
|
else if (matchOpOr(e, e1, e2))
|
||||||
mkBool(v, evalBool(env, e1) || evalBool(env, e2));
|
mkBool(v, evalBool(env, e1) || evalBool(env, e2));
|
||||||
return;
|
|
||||||
|
/* Attribute set update (//). */
|
||||||
|
else if (matchOpUpdate(e, e1, e2)) {
|
||||||
|
v.type = tAttrs;
|
||||||
|
v.attrs = new Bindings;
|
||||||
|
|
||||||
|
Value v2;
|
||||||
|
eval(env, e2, v2);
|
||||||
|
foreach (Bindings::iterator, i, *v2.attrs)
|
||||||
|
(*v.attrs)[i->first] = i->second;
|
||||||
|
|
||||||
|
eval(env, e1, v2);
|
||||||
|
foreach (Bindings::iterator, i, *v2.attrs)
|
||||||
|
if (v.attrs->find(i->first) == v.attrs->end())
|
||||||
|
(*v.attrs)[i->first] = i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error("unsupported term");
|
/* Attribute existence test (?). */
|
||||||
|
else if (matchOpHasAttr(e, e1, name)) {
|
||||||
|
eval(env, e1, v);
|
||||||
|
forceAttrs(v);
|
||||||
|
mkBool(v, v.attrs->find(name) != v.attrs->end());
|
||||||
|
}
|
||||||
|
|
||||||
|
else throw Error("unsupported term");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -637,6 +678,18 @@ void EvalState::forceFunction(Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string EvalState::forceStringNoCtx(Value & v)
|
||||||
|
{
|
||||||
|
forceValue(v);
|
||||||
|
if (v.type != tString)
|
||||||
|
throw TypeError(format("value is %1% while a string was expected") % showType(v));
|
||||||
|
if (v.string.context)
|
||||||
|
throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
|
||||||
|
% v.string.s % v.string.context[0]);
|
||||||
|
return string(v.string.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
string EvalState::coerceToString(Value & v, PathSet & context,
|
string EvalState::coerceToString(Value & v, PathSet & context,
|
||||||
bool coerceMore, bool copyToStore)
|
bool coerceMore, bool copyToStore)
|
||||||
{
|
{
|
||||||
|
@ -901,68 +954,6 @@ LocalNoInline(ATerm expandRec(EvalState & state, ATerm e, ATermList rbnds, ATerm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LocalNoInline(Expr updateAttrs(Expr e1, Expr e2))
|
|
||||||
{
|
|
||||||
/* Note: e1 and e2 should be in normal form. */
|
|
||||||
|
|
||||||
ATermMap attrs;
|
|
||||||
queryAllAttrs(e1, attrs, true);
|
|
||||||
queryAllAttrs(e2, attrs, true);
|
|
||||||
|
|
||||||
return makeAttrs(attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string evalString(EvalState & state, Expr e, PathSet & context)
|
|
||||||
{
|
|
||||||
e = evalExpr(state, e);
|
|
||||||
string s;
|
|
||||||
if (!matchStr(e, s, context))
|
|
||||||
throwTypeError("value is %1% while a string was expected", showType(e));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string evalStringNoCtx(EvalState & state, Expr e)
|
|
||||||
{
|
|
||||||
PathSet context;
|
|
||||||
string s = evalString(state, e, context);
|
|
||||||
if (!context.empty())
|
|
||||||
throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
|
|
||||||
% s % *(context.begin()));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int evalInt(EvalState & state, Expr e)
|
|
||||||
{
|
|
||||||
e = evalExpr(state, e);
|
|
||||||
int i;
|
|
||||||
if (!matchInt(e, i))
|
|
||||||
throwTypeError("value is %1% while an integer was expected", showType(e));
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool evalBool(EvalState & state, Expr e)
|
|
||||||
{
|
|
||||||
e = evalExpr(state, e);
|
|
||||||
if (e == eTrue) return true;
|
|
||||||
else if (e == eFalse) return false;
|
|
||||||
else throwTypeError("value is %1% while a boolean was expected", showType(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ATermList evalList(EvalState & state, Expr e)
|
|
||||||
{
|
|
||||||
e = evalExpr(state, e);
|
|
||||||
ATermList list;
|
|
||||||
if (!matchList(e, list))
|
|
||||||
throwTypeError("value is %1% while a list was expected", showType(e));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void flattenList(EvalState & state, Expr e, ATermList & result)
|
static void flattenList(EvalState & state, Expr e, ATermList & result)
|
||||||
{
|
{
|
||||||
ATermList es;
|
ATermList es;
|
||||||
|
@ -1078,14 +1069,6 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos))
|
|
||||||
{
|
|
||||||
if (!evalBool(state, cond))
|
|
||||||
throw AssertionError(format("assertion failed at %1%") % showPos(pos));
|
|
||||||
return evalExpr(state, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos))
|
LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos))
|
||||||
{
|
{
|
||||||
ATermMap attrs;
|
ATermMap attrs;
|
||||||
|
@ -1109,14 +1092,6 @@ LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LocalNoInline(Expr evalHasAttr(EvalState & state, Expr e, ATerm name))
|
|
||||||
{
|
|
||||||
ATermMap attrs;
|
|
||||||
queryAllAttrs(evalExpr(state, e), attrs);
|
|
||||||
return makeBool(attrs.get(name) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e))
|
LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e))
|
||||||
{
|
{
|
||||||
Expr e1, e2;
|
Expr e1, e2;
|
||||||
|
@ -1177,19 +1152,6 @@ LocalNoInline(Expr evalSubPath(EvalState & state, Expr e1, Expr e2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LocalNoInline(Expr evalOpConcat(EvalState & state, Expr e1, Expr e2))
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
ATermList l1 = evalList(state, e1);
|
|
||||||
ATermList l2 = evalList(state, e2);
|
|
||||||
return makeList(ATconcat(l1, l2));
|
|
||||||
} catch (Error & e) {
|
|
||||||
addErrorPrefix(e, "in a list concatenation:\n");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Implementation of the `==' and `!=' operators. */
|
/* Implementation of the `==' and `!=' operators. */
|
||||||
LocalNoInline(bool areEqual(EvalState & state, Expr e1, Expr e2))
|
LocalNoInline(bool areEqual(EvalState & state, Expr e1, Expr e2))
|
||||||
{
|
{
|
||||||
|
|
|
@ -104,19 +104,9 @@ static inline void mkBool(Value & v, bool b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void mkString(Value & v, const char * s)
|
void mkString(Value & v, const char * s);
|
||||||
{
|
void mkString(Value & v, const string & s, const PathSet & context);
|
||||||
v.type = tString;
|
void mkPath(Value & v, const char * s);
|
||||||
v.string.s = s;
|
|
||||||
v.string.context = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void mkPath(Value & v, const char * s)
|
|
||||||
{
|
|
||||||
v.type = tPath;
|
|
||||||
v.path = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<Path, PathSet> DrvRoots;
|
typedef std::map<Path, PathSet> DrvRoots;
|
||||||
|
@ -177,6 +167,7 @@ public:
|
||||||
void forceAttrs(Value & v);
|
void forceAttrs(Value & v);
|
||||||
void forceList(Value & v);
|
void forceList(Value & v);
|
||||||
void forceFunction(Value & v); // either lambda or primop
|
void forceFunction(Value & v); // either lambda or primop
|
||||||
|
string forceStringNoCtx(Value & v);
|
||||||
|
|
||||||
/* String coercion. Converts strings, paths and derivations to a
|
/* String coercion. Converts strings, paths and derivations to a
|
||||||
string. If `coerceMore' is set, also converts nulls, integers,
|
string. If `coerceMore' is set, also converts nulls, integers,
|
||||||
|
@ -234,7 +225,6 @@ Expr strictEvalExpr(EvalState & state, Expr e);
|
||||||
|
|
||||||
/* Specific results. */
|
/* Specific results. */
|
||||||
string evalString(EvalState & state, Expr e, PathSet & context);
|
string evalString(EvalState & state, Expr e, PathSet & context);
|
||||||
string evalStringNoCtx(EvalState & state, Expr e);
|
|
||||||
int evalInt(EvalState & state, Expr e);
|
int evalInt(EvalState & state, Expr e);
|
||||||
bool evalBool(EvalState & state, Expr e);
|
bool evalBool(EvalState & state, Expr e);
|
||||||
ATermList evalList(EvalState & state, Expr e);
|
ATermList evalList(EvalState & state, Expr e);
|
||||||
|
|
|
@ -687,24 +687,32 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v)
|
||||||
|
|
||||||
return makeList(list);
|
return makeList(list);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic version of the `.' operator. */
|
/* Dynamic version of the `.' operator. */
|
||||||
static void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
static void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = evalStringNoCtx(state, args[0]);
|
string attr = state.forceStringNoCtx(*args[0]);
|
||||||
return evalExpr(state, makeSelect(args[1], toATerm(attr)));
|
state.forceAttrs(*args[1]);
|
||||||
|
Bindings::iterator i = args[1]->attrs->find(toATerm(attr));
|
||||||
|
if (i == args[1]->attrs->end())
|
||||||
|
throw EvalError(format("attribute `%1%' missing") % attr);
|
||||||
|
state.forceValue(i->second);
|
||||||
|
v = i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic version of the `?' operator. */
|
/* Dynamic version of the `?' operator. */
|
||||||
static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
|
static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = evalStringNoCtx(state, args[0]);
|
string attr = state.forceStringNoCtx(*args[0]);
|
||||||
return evalExpr(state, makeOpHasAttr(args[1], toATerm(attr)));
|
state.forceAttrs(*args[1]);
|
||||||
|
mkBool(v, args[1]->attrs->find(toATerm(attr)) != args[1]->attrs->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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;}
|
||||||
... {name = "nameN"; value = valueN;}] is transformed to {name1 =
|
... {name = "nameN"; value = valueN;}] is transformed to {name1 =
|
||||||
|
@ -896,31 +904,24 @@ static void prim_add(EvalState & state, Value * * args, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void prim_sub(EvalState & state, Value * * args, Value & v)
|
static void prim_sub(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
int i1 = evalInt(state, args[0]);
|
mkInt(v, state.forceInt(*args[0]) - state.forceInt(*args[1]));
|
||||||
int i2 = evalInt(state, args[1]);
|
|
||||||
return makeInt(i1 - i2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void prim_mul(EvalState & state, Value * * args, Value & v)
|
static void prim_mul(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
int i1 = evalInt(state, args[0]);
|
mkInt(v, state.forceInt(*args[0]) * state.forceInt(*args[1]));
|
||||||
int i2 = evalInt(state, args[1]);
|
|
||||||
return makeInt(i1 * i2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void prim_div(EvalState & state, Value * * args, Value & v)
|
static void prim_div(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
int i1 = evalInt(state, args[0]);
|
int i2 = state.forceInt(*args[1]);
|
||||||
int i2 = evalInt(state, args[1]);
|
|
||||||
if (i2 == 0) throw EvalError("division by zero");
|
if (i2 == 0) throw EvalError("division by zero");
|
||||||
return makeInt(i1 / i2);
|
mkInt(v, state.forceInt(*args[0]) / i2);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static void prim_lessThan(EvalState & state, Value * * args, Value & v)
|
static void prim_lessThan(EvalState & state, Value * * args, Value & v)
|
||||||
|
@ -941,36 +942,36 @@ static void prim_toString(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(*args[0], context, true, false);
|
string s = state.coerceToString(*args[0], context, true, false);
|
||||||
mkString(v, strdup(s.c_str())); // !!! context
|
mkString(v, s.c_str()); // !!! context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* `substring start len str' returns the substring of `str' starting
|
/* `substring start len str' returns the substring of `str' starting
|
||||||
at character position `min(start, stringLength str)' inclusive and
|
at character position `min(start, stringLength str)' inclusive and
|
||||||
ending at `min(start + len, stringLength str)'. `start' must be
|
ending at `min(start + len, stringLength str)'. `start' must be
|
||||||
non-negative. */
|
non-negative. */
|
||||||
static void prim_substring(EvalState & state, Value * * args, Value & v)
|
static void prim_substring(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
int start = evalInt(state, args[0]);
|
int start = state.forceInt(*args[0]);
|
||||||
int len = evalInt(state, args[1]);
|
int len = state.forceInt(*args[1]);
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = coerceToString(state, args[2], context);
|
string s = state.coerceToString(*args[2], context);
|
||||||
|
|
||||||
if (start < 0) throw EvalError("negative start position in `substring'");
|
if (start < 0) throw EvalError("negative start position in `substring'");
|
||||||
|
|
||||||
return makeStr(string(s, start, len), context);
|
mkString(v, string(s, start, len), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void prim_stringLength(EvalState & state, Value * * args, Value & v)
|
static void prim_stringLength(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = coerceToString(state, args[0], context);
|
string s = state.coerceToString(*args[0], context);
|
||||||
return makeInt(s.size());
|
mkInt(v, s.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, Value & v)
|
static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
@ -1078,7 +1079,7 @@ void EvalState::createBaseEnv()
|
||||||
mkInt(v, time(0));
|
mkInt(v, time(0));
|
||||||
addConstant("__currentTime", v);
|
addConstant("__currentTime", v);
|
||||||
|
|
||||||
mkString(v, strdup(thisSystem.c_str()));
|
mkString(v, thisSystem.c_str());
|
||||||
addConstant("__currentSystem", v);
|
addConstant("__currentSystem", v);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
|
@ -1120,8 +1121,10 @@ void EvalState::createBaseEnv()
|
||||||
|
|
||||||
// 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);
|
||||||
addPrimOp("__listToAttrs", 1, prim_listToAttrs);
|
addPrimOp("__listToAttrs", 1, prim_listToAttrs);
|
||||||
|
@ -1140,18 +1143,16 @@ void EvalState::createBaseEnv()
|
||||||
|
|
||||||
// Integer arithmetic
|
// Integer arithmetic
|
||||||
addPrimOp("__add", 2, prim_add);
|
addPrimOp("__add", 2, prim_add);
|
||||||
#if 0
|
|
||||||
addPrimOp("__sub", 2, prim_sub);
|
addPrimOp("__sub", 2, prim_sub);
|
||||||
addPrimOp("__mul", 2, prim_mul);
|
addPrimOp("__mul", 2, prim_mul);
|
||||||
addPrimOp("__div", 2, prim_div);
|
addPrimOp("__div", 2, prim_div);
|
||||||
#endif
|
|
||||||
addPrimOp("__lessThan", 2, prim_lessThan);
|
addPrimOp("__lessThan", 2, prim_lessThan);
|
||||||
|
|
||||||
// String manipulation
|
// String manipulation
|
||||||
addPrimOp("toString", 1, prim_toString);
|
addPrimOp("toString", 1, prim_toString);
|
||||||
#if 0
|
|
||||||
addPrimOp("__substring", 3, prim_substring);
|
addPrimOp("__substring", 3, prim_substring);
|
||||||
addPrimOp("__stringLength", 1, prim_stringLength);
|
addPrimOp("__stringLength", 1, prim_stringLength);
|
||||||
|
#if 0
|
||||||
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||||
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,13 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
bool parseOnly, bool strict, const ATermMap & autoArgs,
|
bool parseOnly, bool strict, const ATermMap & autoArgs,
|
||||||
bool evalOnly, bool xmlOutput, Expr e)
|
bool evalOnly, bool xmlOutput, Expr e)
|
||||||
{
|
{
|
||||||
|
if (parseOnly)
|
||||||
|
std::cout << format("%1%\n") % canonicaliseExpr(e);
|
||||||
|
else {
|
||||||
Value v;
|
Value v;
|
||||||
state.strictEval(e, v);
|
state.strictEval(e, v);
|
||||||
std::cout << v << std::endl;
|
std::cout << v << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for (Strings::const_iterator i = attrPaths.begin(); i != attrPaths.end(); ++i) {
|
for (Strings::const_iterator i = attrPaths.begin(); i != attrPaths.end(); ++i) {
|
||||||
|
|
Loading…
Reference in a new issue