* Fixed builtins.genericClosure.
This commit is contained in:
parent
fe2d869e04
commit
0777448ca6
3 changed files with 61 additions and 25 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue