diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc
index db54011384d6..6f686bd6b604 100644
--- a/src/libexpr/eval-test.cc
+++ b/src/libexpr/eval-test.cc
@@ -29,6 +29,8 @@ typedef enum {
tInt = 1,
tBool,
tString,
+ tPath,
+ tNull,
tAttrs,
tList,
tThunk,
@@ -157,6 +159,23 @@ std::ostream & operator << (std::ostream & str, Value & v)
static void eval(Env & env, Expr e, Value & v);
+string showType(Value & v)
+{
+ switch (v.type) {
+ case tString: return "a string";
+ case tPath: return "a path";
+ case tNull: return "null";
+ case tInt: return "an integer";
+ case tBool: return "a boolean";
+ case tLambda: return "a function";
+ case tAttrs: return "an attribute set";
+ case tList: return "a list";
+ case tPrimOpApp: return "a partially applied built-in function";
+ default: throw Error("unknown type");
+ }
+}
+
+
static void forceValue(Value & v)
{
if (v.type == tThunk) {
@@ -172,6 +191,30 @@ static void forceValue(Value & v)
}
+static void forceInt(Value & v)
+{
+ forceValue(v);
+ if (v.type != tInt)
+ throw TypeError(format("value is %1% while an integer was expected") % showType(v));
+}
+
+
+static void forceAttrs(Value & v)
+{
+ forceValue(v);
+ if (v.type != tAttrs)
+ throw TypeError(format("value is %1% while an attribute set was expected") % showType(v));
+}
+
+
+static void forceList(Value & v)
+{
+ forceValue(v);
+ if (v.type != tList)
+ throw TypeError(format("value is %1% while a list was expected") % showType(v));
+}
+
+
static Value * lookupWith(Env * env, Sym name)
{
if (!env) return 0;
@@ -247,7 +290,7 @@ static bool eqValues(Value & v1, Value & v2)
}
-unsigned long nrValues = 0, nrEnvs = 0;
+unsigned long nrValues = 0, nrEnvs = 0, nrEvaluated = 0;
static Value * allocValues(unsigned int count)
{
@@ -272,6 +315,8 @@ static void eval(Env & env, Expr e, Value & v)
printMsg(lvlError, format("eval: %1%") % e);
+ nrEvaluated++;
+
Sym name;
if (matchVar(e, name)) {
Value * v2 = lookupVar(&env, name);
@@ -328,7 +373,7 @@ static void eval(Env & env, Expr e, Value & v)
Expr e1, e2;
if (matchSelect(e, e2, name)) {
eval(env, e2, v);
- if (v.type != tAttrs) throw TypeError("expected attribute set");
+ forceAttrs(v); // !!! eval followed by force is slightly inefficient
Bindings::iterator i = v.attrs->find(name);
if (i == v.attrs->end()) throw TypeError("attribute not found");
forceValue(i->second);
@@ -409,7 +454,7 @@ static void eval(Env & env, Expr e, Value & v)
}
eval(env, arg, *vArg);
- if (vArg->type != tAttrs) throw TypeError("expected attribute set");
+ forceAttrs(*vArg);
/* For each formal argument, get the actual argument. If
there is no matching actual argument but the formal
@@ -459,7 +504,7 @@ static void eval(Env & env, Expr e, Value & v)
Value & vAttrs = env2.bindings[sWith];
nrValues++;
eval(env, attrs, vAttrs);
- if (vAttrs.type != tAttrs) throw TypeError("`with' should evaluate to an attribute set");
+ forceAttrs(vAttrs);
eval(env2, body, v);
return;
@@ -490,9 +535,9 @@ static void eval(Env & env, Expr e, Value & v)
if (matchOpConcat(e, e1, e2)) {
Value v1; eval(env, e1, v1);
- if (v1.type != tList) throw TypeError("list expected");
+ forceList(v1);
Value v2; eval(env, e2, v2);
- if (v2.type != tList) throw TypeError("list expected");
+ forceList(v2);
v.type = tList;
v.list.length = v1.list.length + v2.list.length;
v.list.elems = allocValues(v.list.length);
@@ -546,8 +591,7 @@ static void strictEval(Env & env, Expr e, Value & v)
static void prim_head(Value * * args, Value & v)
{
- forceValue(*args[0]);
- if (args[0]->type != tList) throw TypeError("list expected");
+ forceList(*args[0]);
if (args[0]->list.length == 0)
throw Error("`head' called on an empty list");
forceValue(args[0]->list.elems[0]);
@@ -557,10 +601,8 @@ static void prim_head(Value * * args, Value & v)
static void prim_add(Value * * args, Value & v)
{
- forceValue(*args[0]);
- if (args[0]->type != tInt) throw TypeError("integer expected");
- forceValue(*args[1]);
- if (args[1]->type != tInt) throw TypeError("integer expected");
+ forceInt(*args[0]);
+ forceInt(*args[1]);
mkInt(v, args[0]->integer + args[1]->integer);
}
@@ -649,6 +691,7 @@ void run(Strings args)
printMsg(lvlError, format("alloced %1% values") % nrValues);
printMsg(lvlError, format("alloced %1% environments") % nrEnvs);
+ printMsg(lvlError, format("evaluated %1% expressions") % nrEvaluated);
printMsg(lvlError, format("each eval() uses %1% bytes of stack space") % (p1 - p2));
}
|