bwerf's Blog

It's plukalicious
posts - 14, comments - 12, trackbacks - 0, articles - 0

Tuesday, January 20, 2009

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Threading;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            var @this = new Program();

            Console.WriteLine("Main before");

            try

            {

                @this.Outer().Invoke();

            }

            catch (Exception e)

            {

                Console.WriteLine("Main caught exception!");

                Console.WriteLine(e);

            }

            Console.WriteLine("Main after");

            Console.ReadLine();

        }

 

        IEnumerable<IContinuation> Outer()

        {

            Console.WriteLine("Outer before");

 

            /* what i want:

             * yield Inner2();

             */

 

            yield return Inner2().PrepareYield();

 

            /* What i want to type: (give me a way to extend the c# language and this is possible :)

             * try

             * {

             *     int result = yield Inner();

             * }

             * catch

             * {

                   Console.WriteLine("Caught exception!");

             * }

             *

             * This does two things, receiving exceptions thrown from a child continuation, and return values.

             */

 

            // What i needed to type:

            int result;

            Holder<int> r = new Holder<int>();

            var y = Inner(r).PrepareYieldAndComplete();

            yield return y;

            try

            {

                y.Complete();

                result = r.Value;

            }

            catch (Exception e)

            {

                Console.WriteLine("Outer caught exception!");

                Console.WriteLine(e);

                throw;

            }

            Console.WriteLine("Outer after");

        }

 

        IEnumerable<IContinuation> Inner(Holder<int> result)

        {

            Console.WriteLine("Inner before");

            if (result != null)

            throw new Exception();

            //Console.WriteLine("Inner after");

            yield break;

        }

 

        IEnumerable<IContinuation> Inner2()

        {

            Console.WriteLine("Inner2 before");

            Console.WriteLine("Inner2 after");

            yield break;

        }

    }

 

    class Holder<T>

    {

        public T Value { get; set; }

    }

 

    interface IContinuation

    {

        IEnumerable<WaitHandle> Handles();

        bool Process();

    }

 

    interface IPassThroughContinuation : IContinuation

    {

        void Complete();

    }

 

    static class ContinationExtensions

    {

        public static IPassThroughContinuation PrepareYieldAndComplete(this IEnumerable<IContinuation> self)

        {

            return new PassThroughContinuation(self);

        }

 

        public static IContinuation PrepareYield(this IEnumerable<IContinuation> self)

        {

            return new CombinedContinuation(self);

        }

 

        public static bool WaitAny(this IEnumerable<WaitHandle> self)

        {

            if (self == null)

                return true;

            foreach (var w in self)

                if (w.WaitOne(0, false))

                    return true;

            return false;

        }

 

        public static void Invoke(this IEnumerable<IContinuation> self)

        {

            var c = self.PrepareYield();

            while (true)

            {

                c.Handles().WaitAny();

                if (!c.Process())

                    break;

            }

        }

    }

 

    class PassThroughContinuation : IPassThroughContinuation

    {

        private IEnumerator<IContinuation> source;

        private Exception exception;

        private bool done;

        private IContinuation value;

 

        public PassThroughContinuation(IEnumerable<IContinuation> source)

        {

            this.source = source.GetEnumerator();

        }

 

        public IEnumerable<WaitHandle> Handles()

        {

            if (done||(value == null))

                return null;

            return value.Handles();

        }

 

        public bool Process()

        {

            if (done)

                return false;

            try

            {

                if (value != null)

                    if (value.Process())

                        return true;

                if (!source.MoveNext())

                {

                    done = true;

                    return false;

                }

                value = source.Current;

                return true;

            }

            catch (ContinuationException ce)

            {

                exception = ce.InnerException;

                done = true;

                return false;

            }

            catch (Exception e)

            {

                exception = e;

                done = true;

                return false;

            }

        }

 

        public void Complete()

        {

            if (!done)

                throw new InvalidOperationException();

            if (exception != null)

                throw new ContinuationException(exception);

        }

    }

 

    class CombinedContinuation : IContinuation

    {

        private IEnumerator<IContinuation> source;

        private bool done;

        private IContinuation value;

 

        public CombinedContinuation(IEnumerable<IContinuation> source)

        {

            this.source = source.GetEnumerator();

        }

 

        public IEnumerable<WaitHandle> Handles()

        {

            if (done || (value == null))

                return null;

            return value.Handles();

        }

 

        public bool Process()

        {

            if (done)

                return false;

            try

            {

                if (value != null)

                    if (value.Process())

                        return true;

                if (!source.MoveNext())

                {

                    done = true;

                    return false;

                }

                value = source.Current;

                return true;

            }

            catch

            {

                done = true;

                throw;

            }

        }

 

    }

 

    class ContinuationException : Exception

    {

        public ContinuationException(Exception exception)

            : base("Exception raised inside a continuation", exception)

        {

        }

    }

}

 

 

posted @ 9:50 PM | Feedback (0)