* Fixed builtins.genericClosure.

This commit is contained in:
Eelco Dolstra 2010-04-21 15:57:11 +00:00
parent fe2d869e04
commit 0777448ca6
3 changed files with 61 additions and 25 deletions

View File

@ -73,21 +73,25 @@ std::ostream & operator << (std::ostream & str, Value & v)
} }
string showType(Value & v) string showType(const Value & v)
{ {
switch (v.type) { switch (v.type) {
case tInt: return "an integer"; case tInt: return "an integer";
case tBool: return "a boolean"; case tBool: return "a boolean";
case tString: return "a string"; case tString: return "a string";
case tPath: return "a path"; case tPath: return "a path";
case tNull: return "null";
case tAttrs: return "an attribute set"; case tAttrs: return "an attribute set";
case tList: return "a list"; 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 tLambda: return "a function";
case tCopy: return "a copy";
case tBlackhole: return "a black hole";
case tPrimOp: return "a built-in function"; case tPrimOp: return "a built-in function";
case tPrimOpApp: return "a partially applied built-in function"; case tPrimOpApp: return "a partially applied built-in function";
default: throw Error(format("unknown type: %1%") % v.type);
} }
abort();
} }

View File

@ -304,7 +304,7 @@ private:
/* Return a string representing the type of the value `v'. */ /* Return a string representing the type of the value `v'. */
string showType(Value & v); string showType(const Value & v);
} }

View File

@ -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) static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
{ {
startNest(nest, lvlDebug, "finding dependencies"); startNest(nest, lvlDebug, "finding dependencies");
@ -98,45 +117,60 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
throw EvalError("attribute `startSet' required"); throw EvalError("attribute `startSet' required");
state.forceList(startSet->second); state.forceList(startSet->second);
list<Value> workSet; list<Value *> workSet;
for (unsigned int n = 0; n < startSet->second.list.length; ++n) 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. */ /* Get the operator. */
Bindings::iterator op = Bindings::iterator op =
args[0]->attrs->find(state.symbols.create("operator")); args[0]->attrs->find(state.symbols.create("operator"));
if (op == args[0]->attrs->end()) if (op == args[0]->attrs->end())
throw EvalError("attribute `operator' required"); throw EvalError("attribute `operator' required");
state.forceValue(op->second);
/* Construct the closure by applying the operator to element of /* Construct the closure by applying the operator to element of
`workSet', adding the result to `workSet', continuing until `workSet', adding the result to `workSet', continuing until
no new elements are found. */ no new elements are found. */
list<Value> res; list<Value> res;
set<Expr> doneKeys; // !!! gc roots set<Value, CompareValues> doneKeys;
while (!workSet.empty()) { while (!workSet.empty()) {
Expr e = *(workSet.begin()); Value * e = *(workSet.begin());
workSet.erase(e); workSet.pop_front();
e = strictEvalExpr(state, e); state.forceAttrs(*e);
Expr key = queryAttr(e, "key"); Bindings::iterator key =
if (!key) throw EvalError("attribute `key' required"); 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; if (doneKeys.find(key->second) != doneKeys.end()) continue;
doneKeys.insert(key); doneKeys.insert(key->second);
res = ATinsert(res, e); res.push_back(*e);
/* Call the `operator' function with `e' as argument. */ /* Call the `operator' function with `e' as argument. */
ATermList res = evalList(state, makeCall(op, e)); Value call;
mkApp(call, op->second, *e);
state.forceList(call);
/* Try to find the dependencies relative to the `path'. */ /* Add the values returned by the operator to the work set. */
for (ATermIterator i(res); i; ++i) for (unsigned int n = 0; n < call.list.length; ++n) {
workSet.insert(evalExpr(state, *i)); 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) static void prim_abort(EvalState & state, Value * * args, Value & v)
@ -1017,9 +1051,7 @@ void EvalState::createBaseEnv()
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 #if 0