aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-04-21 15:57:11 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-04-21 15:57:11 +0000
commit0777448ca68175b6daf3d8f5374cf43523828c47 (patch)
tree97ca8970da851edfe568ad3e19ec06dc318ad7fd
parentfe2d869e04372de69719c3989a75247ff44b8fd4 (diff)
* Fixed builtins.genericClosure.
-rw-r--r--src/libexpr/eval.cc10
-rw-r--r--src/libexpr/eval.hh2
-rw-r--r--src/libexpr/primops.cc76
3 files changed, 62 insertions, 26 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index f59ea99e5..0e4f2519a 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -73,21 +73,25 @@ std::ostream & operator << (std::ostream & str, Value & v)
}
-string showType(Value & v)
+string showType(const Value & v)
{
switch (v.type) {
case tInt: return "an integer";
case tBool: return "a boolean";
case tString: return "a string";
case tPath: return "a path";
+ case tNull: return "null";
case tAttrs: return "an attribute set";
case tList: return "a list";
- case tNull: return "null";
+ case tThunk: return "a thunk";
+ case tApp: return "a function application";
case tLambda: return "a function";
+ case tCopy: return "a copy";
+ case tBlackhole: return "a black hole";
case tPrimOp: return "a built-in function";
case tPrimOpApp: return "a partially applied built-in function";
- default: throw Error(format("unknown type: %1%") % v.type);
}
+ abort();
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index a730dc297..aff68ea2a 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -304,7 +304,7 @@ private:
/* Return a string representing the type of the value `v'. */
-string showType(Value & v);
+string showType(const Value & v);
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index a228398e0..9023d2b1b 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -84,7 +84,26 @@ static void prim_isBool(EvalState & state, Value * * args, Value & v)
}
-#if 0
+struct CompareValues
+{
+ bool operator () (const Value & v1, const Value & v2) const
+ {
+ if (v1.type != v2.type)
+ throw EvalError("cannot compare values of different types");
+ switch (v1.type) {
+ case tInt:
+ return v1.integer < v2.integer;
+ case tString:
+ return strcmp(v1.string.s, v2.string.s) < 0;
+ case tPath:
+ return strcmp(v1.path, v2.path) < 0;
+ default:
+ throw EvalError(format("cannot compare %1% with %2%") % showType(v1) % showType(v2));
+ }
+ }
+};
+
+
static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
{
startNest(nest, lvlDebug, "finding dependencies");
@@ -98,45 +117,60 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
throw EvalError("attribute `startSet' required");
state.forceList(startSet->second);
- list<Value> workSet;
+ list<Value *> workSet;
for (unsigned int n = 0; n < startSet->second.list.length; ++n)
- workSet.push_back(*startSet->second.list.elems[n]);
+ workSet.push_back(startSet->second.list.elems[n]);
/* Get the operator. */
Bindings::iterator op =
args[0]->attrs->find(state.symbols.create("operator"));
if (op == args[0]->attrs->end())
throw EvalError("attribute `operator' required");
-
+ state.forceValue(op->second);
+
/* Construct the closure by applying the operator to element of
`workSet', adding the result to `workSet', continuing until
no new elements are found. */
list<Value> res;
- set<Expr> doneKeys; // !!! gc roots
+ set<Value, CompareValues> doneKeys;
while (!workSet.empty()) {
- Expr e = *(workSet.begin());
- workSet.erase(e);
+ Value * e = *(workSet.begin());
+ workSet.pop_front();
- e = strictEvalExpr(state, e);
+ state.forceAttrs(*e);
- Expr key = queryAttr(e, "key");
- if (!key) throw EvalError("attribute `key' required");
+ Bindings::iterator key =
+ e->attrs->find(state.symbols.create("key"));
+ if (key == e->attrs->end())
+ throw EvalError("attribute `key' required");
+ state.forceValue(key->second);
- if (doneKeys.find(key) != doneKeys.end()) continue;
- doneKeys.insert(key);
- res = ATinsert(res, e);
+ if (doneKeys.find(key->second) != doneKeys.end()) continue;
+ doneKeys.insert(key->second);
+ res.push_back(*e);
/* Call the `operator' function with `e' as argument. */
- ATermList res = evalList(state, makeCall(op, e));
-
- /* Try to find the dependencies relative to the `path'. */
- for (ATermIterator i(res); i; ++i)
- workSet.insert(evalExpr(state, *i));
+ Value call;
+ mkApp(call, op->second, *e);
+ state.forceList(call);
+
+ /* Add the values returned by the operator to the work set. */
+ for (unsigned int n = 0; n < call.list.length; ++n) {
+ state.forceValue(*call.list.elems[n]);
+ workSet.push_back(call.list.elems[n]);
+ }
}
- return makeList(res);
+ /* Create the result list. */
+ state.mkList(v, res.size());
+ Value * vs = state.allocValues(res.size());
+
+ unsigned int n = 0;
+ foreach (list<Value>::iterator, i, res) {
+ v.list.elems[n] = &vs[n];
+ vs[n++] = *i;
+ }
}
-#endif
static void prim_abort(EvalState & state, Value * * args, Value & v)
@@ -1017,9 +1051,7 @@ void EvalState::createBaseEnv()
addPrimOp("__isString", 1, prim_isString);
addPrimOp("__isInt", 1, prim_isInt);
addPrimOp("__isBool", 1, prim_isBool);
-#if 0
addPrimOp("__genericClosure", 1, prim_genericClosure);
-#endif
addPrimOp("abort", 1, prim_abort);
addPrimOp("throw", 1, prim_throw);
#if 0