Example #1
0
 private void Finish(RoutineException error)
 {
     this.error = error;
     Stop();
     if (parent != null && !parent.isStepping)
     {
         parent.Step();
     }
 }
Example #2
0
 public void Reset()
 {
     Stop();
     enumerator       = null;
     parent           = null;
     returnValue      = null;
     error            = null;
     context          = null;
     exceptionHandler = null;
 }
Example #3
0
        private void Step()
        {
            Assert.IsTrue(!isStepping);
            isStepping = true;

            //Used to detect that routine was killed during step
            var steppingId = id;

            //Running IResumable
            if (enumerator is IResumable)
            {
                var resumer = (resumerPool.Count > 0) ? resumerPool.Pop() : new Resumer();
                resumer.called     = false;
                resumer.routine    = this;
                resumer.steppingId = steppingId;

                var resumable = enumerator as IResumable;
                resumable.Run(resumer);

                //In case of suicide or immediate finish
                if (steppingId != id)
                {
                    return;
                }
            }

            //Running enumerator
            else
            {
                int itCount;
                for (itCount = 0; itCount < Routine.maxIterations; ++itCount)
                {
                    currentReturnValue = null;
                    currentAllReturnValues.Clear();

                    //Bail out if any children are yielding:

                    //Any array: stop if all children are yielding
                    if (finishOnAny)
                    {
                        var childIsDone = true;
                        for (int i = 0, l = children.Count; i < l; ++i)
                        {
                            var child = children[i];

                            if (child.error != null)
                            {
                                Finish(child.error);
                                return;
                            }

                            childIsDone = child.IsDone;
                            if (childIsDone)
                            {
                                currentReturnValue = child.returnValue;
                                break;
                            }
                        }
                        if (!childIsDone)
                        {
                            break;
                        }
                    }

                    //Single or all-array: stop if any children are yielding
                    else
                    {
                        var childIsYielding = false;
                        for (int i = 0, l = children.Count; i < l; ++i)
                        {
                            var child = children[i];

                            if (child.error != null)
                            {
                                Finish(child.error);
                                return;
                            }

                            childIsYielding = !child.IsDone;
                            if (childIsYielding)
                            {
                                break;
                            }
                        }
                        if (childIsYielding)
                        {
                            break;
                        }

                        //Collect return values from children
                        if (arrayWasYielded)
                        {
                            for (int i = 0, l = children.Count; i < l; ++i)
                            {
                                currentAllReturnValues.Add(children[i].returnValue);
                            }
                            currentReturnValue = currentAllReturnValues;
                        }
                        else if (children.Count > 0)
                        {
                            Assert.IsTrue(children.Count == 1);
                            currentReturnValue = children[0].returnValue;
                        }
                    }

                    //Stop and clear children
                    ClearChildren();

                    //Step this routine
                    steppingStack.Push(this);
                    bool             done;
                    RoutineException stepError = null;
                    try
                    {
                        done = !enumerator.MoveNext();
                    }
                    catch (System.Exception e)
                    {
                        stepError = CreateException(e.Message, e);
                        exceptionHandler(stepError, context);
                        done = true;
                    }
                    steppingStack.Pop();

                    //Check for suicide
                    if (steppingId != id)
                    {
                        return;
                    }

                    //Prevent GetResult() from giving back something when it shouldn't
                    currentReturnValue = null;
                    currentAllReturnValues.Clear();

                    //Routine finished?
                    if (done)
                    {
                        Finish(stepError);
                        return;
                    }

                    arrayWasYielded = false;
                    finishOnAny     = false;

                    //Check for yielded array
                    var result = enumerator.Current;
                    if (result is WrappedArray)
                    {
                        var wrappedArray = result as WrappedArray;
                        var arr          = wrappedArray.yieldables;
                        finishOnAny = wrappedArray.isAny;
                        wrappedArrayPool.Push(wrappedArray);

                        if (arr == null)
                        {
                            Finish(CreateException("yieldables not set in WrappedArray"));
                            return;
                        }

                        arrayWasYielded = true;

                        //Copy array contents in case one of contained routines messes with it when stepped
                        Assert.IsTrue(yieldedArray.Count == 0);
                        foreach (var element in arr)
                        {
                            yieldedArray.Add(element);
                        }

                        for (int i = 0, l = yieldedArray.Count; i < l; ++i)
                        {
                            var yieldedValue = yieldedArray[i];
                            if (yieldedValue is IEnumerable)
                            {
                                yieldedValue = (yieldedValue as IEnumerable).GetEnumerator();
                            }
                            else if (!(yieldedValue is IEnumerator))
                            {
                                Finish(CreateException(string.Format("yielded value [{0}] is not an IEnumerator: {1}", i, yieldedValue)));
                                return;
                            }

                            var child = CreateChild(yieldedValue as IEnumerator);

                            //Check for parenticide
                            if (steppingId != id)
                            {
                                return;
                            }

                            //Exit if any child completes in any-array mode
                            if (finishOnAny && child.IsDone)
                            {
                                break;
                            }
                        }

                        yieldedArray.Clear();
                    }

                    //Single runable yielded: create child routine
                    else if (result is IEnumerable)                     //Check for IEnumerable before IEnumerator, as the object could be both (Linq) and we want to treat it as the former if so
                    {
                        CreateChild((result as IEnumerable).GetEnumerator());

                        //Check for parenticide
                        if (steppingId != id)
                        {
                            return;
                        }
                    }
                    else if (result is IEnumerator)
                    {
                        CreateChild(result as IEnumerator);

                        //Check for parenticide
                        if (steppingId != id)
                        {
                            return;
                        }
                    }

                    //Something not-runable was returned
                    else
                    {
                        throw CreateException(string.Format("yielded value is not an IEnumerator or IEnumerable: {0}", result));
                    }
                }
                if (itCount == maxIterations)
                {
                    throw CreateException("Infinite loop in routine!");
                }
            }

            isStepping = false;
        }