Beispiel #1
0
        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;
        }