private IEnumerable<bool> _cooperativeForce(StackContext sctx, Action<PValue> setReturnValue) { if (sctx == null) throw new ArgumentNullException("sctx"); while (true) { //Check if evaluation resulted in exception if (_exception != null) throw _exception; //Check if value is available if (_value != null) break; //Prevent infinite loops if (_blackHole.Trap()) continue; //If we have been trapped, check exception again //Tag thunk as being evaluated _blackHole = BlackHole.Active(Thread.CurrentThread.ManagedThreadId); Debug.Indent(); //We need to save stack space here, so try to invoke via IStackAware // Since most expressions are closures, this has a high success rate var stackAware = _expr.Value as IStackAware; if (stackAware != null) { //Exception handler defined in creation of cooperative context var exprCtx = stackAware.CreateStackContext(sctx, _parameters); sctx.ParentEngine.Stack.AddLast(exprCtx); yield return true; _value = exprCtx.ReturnValue; } else { try { _value = _expr.IndirectCall(sctx, _parameters); } catch (Exception ex) { _blackHole = _blackHole.Inactivate(); _value = PType.Null; _exception = ex; throw; } } Debug.Unindent(); var t = _value.Value as Thunk; if (t != null) { //Assimilate nested thunk _blackHole = t._blackHole; _expr = t._expr; _parameters = t._parameters; _value = t._value; _exception = t._exception; continue; } else { //Release expression _expr = null; _parameters = null; _blackHole = _blackHole.Inactivate(); break; } } setReturnValue(_value); yield break; }