public IObservable <IParseResult <TResult> > Parse(IObservableCursor <TSource> source)
        {
#if !SILVERLIGHT && !PORT_45 && !PORT_40
            using (ParserTraceSources.TraceQueryCompilation(name))
#endif
            {
                IObservable <IParseResult <TResult> > results;

                if (parserFactory == null)
                {
                    results = parse(source);

                    Contract.Assume(results != null);
                }
                else
                {
                    var parser = parserFactory.Value;

                    Contract.Assume(parser != null);

                    results = parser.Parse(source);
                }

                return(results);
            }
        }
Example #2
0
        public ObservableParserCursor(IObservableCursor <T> cursor)
        {
            Contract.Requires(cursor != null);
            Contract.Requires(cursor.IsForwardOnly);

            this.cursor = cursor;
        }
Example #3
0
 public IObservable <IParseResult <TResult> > Parse(IObservableCursor <TSource> source)
 {
     Contract.Requires(source != null);
     Contract.Requires(source.IsForwardOnly);
     Contract.Ensures(Contract.Result <IObservable <IParseResult <TResult> > >() != null);
     return(null);
 }
        public IObservable <IParseResult <IObservable <TResult> > > Parse(IObservableCursor <TSource> source)
        {
            return(Observable.Defer(() =>
            {
                firstParser = null;

                bool first = true;
                var any = new AnyObservableParser <TSource, TResult>(parsers);
                var except = new List <IObservableParser <TSource, TResult> >();

                // See the AllObservableParser.Parse method for an explanation of the optimization that is provided by SelectMany's TContext argument
                var root = source.Branch();
                var rootDisposable = new RefCountDisposable(root);

                return ObservableParseResult.ReturnSuccessMany <TResult>(0)
                .SelectMany(
                    Tuple.Create(root, rootDisposable),
                    parsers.Select(
                        parser => (Func <Tuple <IObservableCursor <TSource>, RefCountDisposable>, Tuple <IParseResult <IObservable <TResult> >, bool>, Tuple <Tuple <IObservableCursor <TSource>, RefCountDisposable>, IObservable <IParseResult <IObservable <TResult> > > > >)
                            ((context, value) =>
                {
                    if (first)
                    {
                        first = false;
                        firstParser = parser;
                    }

                    var branch = context.Item1;
                    var disposable = context.Item2;
                    var refDisposable = disposable.GetDisposable();

                    IObservable <IParseResult <IObservable <TResult> > > results;

                    // Item2 is only true when value.Item1 is the last element of its sequence.
                    if (value.Item2)
                    {
                        branch.Move(value.Item1.Length);

                        results = any.Parse(except, branch)
                                  .Select(result => result.YieldMany())
                                  .Finally(refDisposable.Dispose);
                    }
                    else
                    {
                        branch = branch.Remainder(value.Item1.Length);

                        disposable = new RefCountDisposable(new CompositeDisposable(branch, refDisposable));

                        results = any.Parse(except, branch)
                                  .Select(result => result.YieldMany())
                                  .Finally(disposable.Dispose);
                    }

                    return Tuple.Create(Tuple.Create(branch, disposable), results);
                })),
                    (firstResult, otherResults) => firstResult.Concat(otherResults))
                .Finally(rootDisposable.Dispose);
            }));
        }
        /// <summary>
        /// Applies the parser's grammar, which is defined by <see cref="Start"/>, to generate matches asynchronously.
        /// </summary>
        /// <param name="source">The observable sequence to parse.</param>
        /// <returns>An observable sequence of parse results.</returns>
        public IObservable <TResult> Parse(IObservableCursor <TSource> source)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsForwardOnly);
            Contract.Ensures(Contract.Result <IObservable <TResult> >() != null);

            return(parser.Parse(source).Select(result => result.Value));
        }
        protected virtual ObservableParserCursor <TSource> CreateCursor(IObservableCursor <TSource> source)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsForwardOnly);
            Contract.Ensures(Contract.Result <ObservableParserCursor <TSource> >() != null);

            return(new ObservableParserCursor <TSource>(source));
        }
Example #7
0
        private static IObservable <IParseResult <TResult> > SelectManyInternal <TSource, TFirstResult, TSecondResult, TResult>(
            IObservableCursor <TSource> source,
            IObservableParser <TSource, TFirstResult> firstParser,
            Func <TFirstResult, IObservableParser <TSource, TSecondResult> > secondSelector,
            Func <TFirstResult, TSecondResult, TResult> resultSelector,
            Func <IParseResult <TFirstResult>, IParseResult <TSecondResult>, int> lengthSelector = null)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsForwardOnly);
            Contract.Requires(firstParser != null);
            Contract.Requires(secondSelector != null);
            Contract.Requires(resultSelector != null);
            Contract.Ensures(Contract.Result <IObservable <IParseResult <TResult> > >() != null);

            return(from first in firstParser.Parse(source)
                   from second in Observable.Create <IParseResult <TSecondResult> >(
                       observer =>
            {
                var lookAhead = first as ILookAheadParseResult <TFirstResult>;
                bool hasResult = false;

                var remainder = source.Remainder(first.Length);

                return secondSelector(first.Value)
                .Parse(remainder)
                .Finally(remainder.Dispose)
                .Subscribe(
                    second =>
                {
                    hasResult = true;

                    if (lookAhead != null)
                    {
                        lookAhead.OnCompleted(success: true);

                        observer.OnCompleted();
                    }
                    else
                    {
                        observer.OnNext(second);
                    }
                },
                    observer.OnError,
                    () =>
                {
                    if (!hasResult && lookAhead != null)
                    {
                        lookAhead.OnCompleted(success: false);
                    }

                    observer.OnCompleted();
                });
            })
                   select lengthSelector == null
               ? first.Add(second, resultSelector)
               : first.Yield(second, resultSelector, lengthSelector));
        }
Example #8
0
        [ContractVerification(false)]           // Static checker times out (raised time-out setting to 20 minutes and it still timed out)
        public static IObservableCursor <TSource> Remainder <TSource>(this IObservableCursor <TSource> cursor, int skip)
        {
            Contract.Requires(cursor != null);
            Contract.Requires(skip >= 0);
            Contract.Ensures(cursor.IsSynchronized == Contract.OldValue(cursor.IsSynchronized));
            Contract.Ensures(cursor.IsForwardOnly == Contract.OldValue(cursor.IsForwardOnly));
            Contract.Ensures(Contract.Result <IObservableCursor <TSource> >() != null);
            Contract.Ensures(Contract.Result <IObservableCursor <TSource> >().IsSynchronized == cursor.IsSynchronized);
            Contract.Ensures(Contract.Result <IObservableCursor <TSource> >().IsForwardOnly == cursor.IsForwardOnly);
            Contract.Ensures(cursor.IsSynchronized || Contract.Result <IObservableCursor <TSource> >().IsSequenceTerminated == cursor.IsSequenceTerminated);
            Contract.Ensures(cursor.IsSynchronized || Contract.Result <IObservableCursor <TSource> >().LatestIndex == cursor.LatestIndex);
            Contract.Ensures(cursor.IsSynchronized || Contract.Result <IObservableCursor <TSource> >().CurrentIndex ==
                             (cursor.AtEndOfSequence
        ? cursor.CurrentIndex
        : cursor.IsSequenceTerminated
          ? Math.Min(cursor.CurrentIndex + skip, cursor.LatestIndex + 1)
          : cursor.CurrentIndex + skip));

            var branch = cursor.Branch();

            Contract.Assert(branch.IsSynchronized == cursor.IsSynchronized);
            Contract.Assert(branch.IsSynchronized || branch.IsSequenceTerminated == cursor.IsSequenceTerminated);
            Contract.Assert(branch.IsSynchronized || branch.CurrentIndex == cursor.CurrentIndex);
            Contract.Assert(branch.IsSynchronized || branch.LatestIndex == cursor.LatestIndex);
            Contract.Assert(branch.IsSynchronized || branch.AtEndOfSequence == cursor.AtEndOfSequence);

            if (branch.IsSynchronized)
            {
                branch.Move(skip);
            }
            else if (!branch.AtEndOfSequence)
            {
                int count = skip;

                if (branch.IsSequenceTerminated && branch.CurrentIndex + count > branch.LatestIndex + 1)
                {
                    count = (branch.LatestIndex + 1) - branch.CurrentIndex;

                    Contract.Assert(cursor.CurrentIndex + count == cursor.LatestIndex + 1);
                }

                branch.Move(count);

                Contract.Assert(!branch.IsSynchronized);
                Contract.Assert(branch.CurrentIndex == cursor.CurrentIndex + count);
                Contract.Assert(cursor.IsSequenceTerminated || branch.CurrentIndex == cursor.CurrentIndex + skip);
                Contract.Assume(!cursor.IsSequenceTerminated || cursor.CurrentIndex + skip <= cursor.LatestIndex + 1 || branch.CurrentIndex == cursor.LatestIndex + 1);
                Contract.Assume(!cursor.IsSequenceTerminated || branch.CurrentIndex == Math.Min(cursor.CurrentIndex + skip, cursor.LatestIndex + 1));
            }
            else
            {
                Contract.Assert(branch.CurrentIndex == cursor.CurrentIndex);
            }

            return(branch);
        }
        public SynchronizedObservableCursor(IObservableCursor <T> cursor, object gate = null)
        {
            Contract.Requires(cursor != null);
            Contract.Ensures(IsSynchronized);
            Contract.Ensures(IsForwardOnly == cursor.IsForwardOnly);

            this.cursor = cursor;
            this.gate   = gate ?? new object();

            Contract.Assume(IsForwardOnly == cursor.IsForwardOnly);
        }
Example #10
0
        public IObservable <TResult> Parse(IObservableCursor <char> source, IObservableParser <char, TResult> grammar)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsForwardOnly);
            Contract.Requires(grammar != null);
            Contract.Ensures(Contract.Result <IObservable <TResult> >() != null);

            this.start = grammar;

            return(base.Parse(source));
        }
Example #11
0
        public static IObservableCursor <TSource> Synchronize <TSource>(this IObservableCursor <TSource> cursor)
        {
            Contract.Requires(cursor != null);
            Contract.Ensures(cursor.IsSynchronized == Contract.OldValue(cursor.IsSynchronized));
            Contract.Ensures(cursor.IsForwardOnly == Contract.OldValue(cursor.IsForwardOnly));
            Contract.Ensures(Contract.Result <IObservableCursor <TSource> >() != null);
            Contract.Ensures(Contract.Result <IObservableCursor <TSource> >().IsSynchronized);
            Contract.Ensures(Contract.Result <IObservableCursor <TSource> >().IsForwardOnly == cursor.IsForwardOnly);

            return(new SynchronizedObservableCursor <TSource>(cursor));
        }
        public IObservable <IParseResult <TResult> > Parse(IObservableCursor <TSource> source)
        {
            if (Interlocked.Exchange(ref parsing, 1) == 1)
            {
                throw new InvalidOperationException(Errors.ParseCalledWhileParsing);
            }

            if (cursor != null)
            {
                cursor.Dispose();
            }

            cursor = CreateCursor(source);

            object gate = new object();
            bool   allowSubscription = true;

            return(Observable.Create <IParseResult <TResult> >(
                       observer =>
            {
                lock (gate)
                {
                    if (!allowSubscription)
                    {
                        throw new InvalidOperationException(Errors.ParseSubscribeCalledWhileParsing);
                    }

                    allowSubscription = false;
                }

#if !SILVERLIGHT && !PORT_45 && !PORT_40
                var parse = Observable.Using(() => ParserTraceSources.TraceExecution(Cursor, TraceName), Parse);
#else
                var parse = Parse();
#endif

                var parseSubscription = parse.Subscribe(observer);
                var sourceSubscription = cursor.Connect();

                return new CompositeDisposable(sourceSubscription, parseSubscription);
            })
                   .Finally(() =>
            {
                lock (gate)
                {
                    allowSubscription = true;
                }

                Interlocked.Exchange(ref parsing, 0);
            }));
        }
Example #13
0
        public IObservable <IParseResult <TResult> > Parse(IObservableCursor <TSource> source)
        {
            return(Observable.Defer(() =>
            {
                var completed = new AsyncSubject <Unit>();

                bool hasResult = false;

                return parsers.Select(
                    parser => Observable.Create <IParseResult <TResult> >(
                        observer =>
                {
                    return parser.Parse(source).SubscribeSafe(
                        result =>
                    {
                        if (!hasResult)
                        {
                            hasResult = true;

                            /* The XML lab has shown that Parse may be called multiple times on the same AnyObservableParser
                             * instance during a single Parse operation, sometimes with the same source but most of the time
                             * with a different source; therefore, the selected parser must be reassigned to the latest selection
                             * for each call to Parse, maintaining a local variable (hasResult) to determine whether the current
                             * call to Parse has matched while enumerating the choices.
                             *
                             * It is currently unknown whether it is possible for a nested Parse operation to overwrite the
                             * selected parser, or whether it will have any negative impact.
                             */
                            selectedParser = parser;
                        }

                        observer.OnNext(result);
                    },
                        observer.OnError,
                        () =>
                    {
                        if (hasResult)
                        {
                            completed.OnNext(new Unit());
                            completed.OnCompleted();
                        }

                        observer.OnCompleted();
                    });
                }))
                .Concat()
                .TakeUntil(completed);
            }));
        }
Example #14
0
      public ObservableParserCursorBranch(IObservableCursor<T> branch, Action dispose)
      {
        Contract.Requires(branch != null);
        Contract.Requires(branch.IsForwardOnly);
        Contract.Requires(dispose != null);
        Contract.Ensures(IsSynchronized == branch.IsSynchronized);
        Contract.Ensures(IsForwardOnly == branch.IsForwardOnly);
        Contract.Ensures(IsSynchronized || CurrentIndex == branch.CurrentIndex);
        Contract.Ensures(IsSynchronized || LatestIndex == branch.LatestIndex);
        Contract.Ensures(IsSynchronized || AtEndOfSequence == branch.AtEndOfSequence);
        Contract.Ensures(IsSynchronized || IsSequenceTerminated == branch.IsSequenceTerminated);

        this.branch = branch;
        this.dispose = dispose;
      }
Example #15
0
        internal IObservable <IParseResult <TResult> > Parse(
            ICollection <IObservableParser <TSource, TResult> > except,
            IObservableCursor <TSource> source)
        {
            Contract.Requires(except != null);
            Contract.Requires(!except.IsReadOnly);
            Contract.Requires(source != null);
            Contract.Ensures(Contract.Result <IObservable <IParseResult <TResult> > >() != null);

            return(Observable.Defer(() =>
            {
                var completed = new AsyncSubject <Unit>();

                bool hasResult = false;

                return parsers.Except(except).Select(
                    parser => Observable.Create <IParseResult <TResult> >(
                        observer =>
                {
                    return parser.Parse(source).SubscribeSafe(
                        result =>
                    {
                        if (!hasResult)
                        {
                            hasResult = true;

                            except.Add(parser);
                        }

                        observer.OnNext(result);
                    },
                        observer.OnError,
                        () =>
                    {
                        if (hasResult)
                        {
                            completed.OnNext(new Unit());
                            completed.OnCompleted();
                        }

                        observer.OnCompleted();
                    });
                }))
                .Concat()
                .TakeUntil(completed);
            }));
        }
Example #16
0
        public IObservable <IParseResult <T> > Parse(IObservableCursor <T> source)
        {
            return(Observable.Create <IParseResult <T> >(
                       observer =>
            {
                return source.Subscribe(
                    Observer.Create <T>(
                        value =>
                {
#if !SILVERLIGHT && !PORT_45 && !PORT_40
                    ParserTraceSources.TraceInput(value);
#endif

                    observer.OnNext(ParseResult.Create(value, length: 1));
                },
                        observer.OnError,
                        observer.OnCompleted),
                    count: 1);
            }));
        }
Example #17
0
        private static IObservable <IParseResult <TResult> > SelectManyInternal <TSource, TFirstResult, TCollection, TResult>(
            IObservableCursor <TSource> source,
            IObservableParser <TSource, TFirstResult> parser,
            Func <TFirstResult, IObservable <TCollection> > collectionSelector,
            Func <TFirstResult, TCollection, TResult> resultSelector,
            Func <IParseResult <TFirstResult>, TCollection, int> lengthSelector = null)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsForwardOnly);
            Contract.Requires(parser != null);
            Contract.Requires(collectionSelector != null);
            Contract.Requires(resultSelector != null);
            Contract.Ensures(Contract.Result <IObservable <IParseResult <TResult> > >() != null);

            return(from first in parser.Parse(source)
                   from second in Observable.Create <Tuple <TCollection, bool> >(
                       observer =>
            {
                var lookAhead = first as ILookAheadParseResult <TFirstResult>;
                var hasResult = false;
                TCollection previous = default(TCollection);

                return collectionSelector(first.Value).Subscribe(
                    second =>
                {
                    if (lookAhead != null)
                    {
                        hasResult = true;

                        lookAhead.OnCompleted(success: true);

                        observer.OnCompleted();
                    }
                    else
                    {
                        if (hasResult)
                        {
                            observer.OnNext(Tuple.Create(previous, false));
                        }

                        hasResult = true;
                        previous = second;
                    }
                },
                    observer.OnError,
                    () =>
                {
                    if (hasResult && lookAhead == null)
                    {
                        observer.OnNext(Tuple.Create(previous, true));
                    }
                    else if (!hasResult && lookAhead != null)
                    {
                        lookAhead.OnCompleted(success: false);
                    }

                    observer.OnCompleted();
                });
            })
                   select lengthSelector == null
               ? first.Yield(second.Item1, resultSelector, (f, s) => second.Item2?f.Length : 0)
                   : first.Yield(second.Item1, resultSelector, lengthSelector));
        }
 IObservable <IParseResult <TResult> > IObservableParser <byte, TResult> .Parse(IObservableCursor <byte> source)
 {
     throw new NotSupportedException(Properties.Errors.InlineParseNotSupported);
 }
Example #19
0
 public IObservable <IParseResult <T> > Parse(IObservableCursor <T> source)
 {
     return(ParserCursor.Parse(source));
 }
Example #20
0
        public IObservable <IParseResult <IObservable <TResult> > > Parse(IObservableCursor <TSource> source)
        {
            return(Observable.Defer(() =>
            {
                firstParser = null;

                bool first = true;

                /* The TContext of branches allows for an optimization on top of the previous implementation, which used to create a new
                 * branch for every parse result in every parse result sequence.  This new implementation changes that behavior slightly
                 * by not creating a new branch for the last result in each sequence.  All parser rules (at the time of writing) in Rxx
                 * generate zero or one result only; therefore, the current branch can be moved forward and reused by child sequences
                 * without affecting the parent result sequence, because it's already completed.  This optimization has proven to be
                 * slightly beneficial across normal parser queries that use And, All and Exactly operators.  It should also be beneficial
                 * for multi-result queries since most of the individual parser rules in these queries will only generate a single result.
                 * A new branch would only be created for each result in the multi-result sequence.  Scalar-result parsers that follow
                 * sequentially in the All query would simply move their shared parent branch instead of creating new branches.
                 */
                var root = source.Branch();
                var rootDisposable = new RefCountDisposable(root);

                return ObservableParseResult.ReturnSuccessMany <TResult>(0)
                .SelectMany(
                    Tuple.Create(root, rootDisposable),
                    parsers.Select(
                        parser => (Func <Tuple <IObservableCursor <TSource>, RefCountDisposable>, Tuple <IParseResult <IObservable <TResult> >, bool>, Tuple <Tuple <IObservableCursor <TSource>, RefCountDisposable>, IObservable <IParseResult <IObservable <TResult> > > > >)
                            ((context, value) =>
                {
                    if (first)
                    {
                        first = false;
                        firstParser = parser;
                    }

                    var branch = context.Item1;
                    var disposable = context.Item2;
                    var refDisposable = disposable.GetDisposable();

                    IObservable <IParseResult <IObservable <TResult> > > results;

                    // Item2 is only true when value.Item1 is the last element of its sequence.
                    if (value.Item2)
                    {
                        branch.Move(value.Item1.Length);

                        results = parser.Parse(branch)
                                  .Select(result => result.YieldMany())
                                  .Finally(refDisposable.Dispose);
                    }
                    else
                    {
                        branch = branch.Remainder(value.Item1.Length);

                        disposable = new RefCountDisposable(new CompositeDisposable(branch, refDisposable));

                        results = parser.Parse(branch)
                                  .Select(result => result.YieldMany())
                                  .Finally(disposable.Dispose);
                    }

                    return Tuple.Create(Tuple.Create(branch, disposable), results);
                })),
                    (firstResult, otherResults) => firstResult.Concat(otherResults))
                .Finally(rootDisposable.Dispose);
            }));
        }
Example #21
0
 IObservable <IParseResult <char> > IObservableParser <char, char> .Parse(IObservableCursor <char> source)
 {
     throw new NotSupportedException(Properties.Errors.InlineParseNotSupported);
 }
 IObservable <IParseResult <TResult> > IObservableParser <TSource, TResult> .Parse(IObservableCursor <TSource> source)
 {
     return(parser.Parse(source));
 }
        public IObservable <IParseResult <IObservable <TResult> > > Parse(IObservableCursor <TSource> source)
        {
            return(Observable.Create <IParseResult <IObservable <TResult> > >(
                       observer =>
            {
                int matchCount = 0;
                int remainingLength = 0;

                Action <Action> iterate = moveNext =>
                {
                    bool hasResult = false;
                    int length = 0;

                    var branch = source.Branch();

                    var values = parser.Parse(branch)
                                 .Finally(branch.Dispose)
                                 .Select(result =>
                    {
                        if (!hasResult)
                        {
                            matchCount++;
                            hasResult = true;
                        }

                        length = Math.Max(length, result.Length);

                        return result.Value;
                    })
                                 .Do(
                        __ => { },
                        () =>
                    {
                        /* We must respect the greediness of the results unless the length is zero since the
                         * cursor would have already moved to the following element.  It is acceptable to ignore
                         * zero-length results because marking an entirely non-greedy parser as ambiguous would
                         * otherwise cause the parser to continously parse the first element indefinitely.
                         */
                        if (length > 0)
                        {
                            remainingLength = length - 1;
                        }
                        else if (remainingLength > 0)
                        {
                            remainingLength--;
                        }

                        moveNext();
                    });

                    observer.OnNext(ParseResult.Create(values, length: 1));
                };

                Action complete = () =>
                {
                    if (remainingLength > 0)
                    {
                        observer.OnNext(ObservableParseResult.SuccessMany <TResult>(remainingLength));
                    }

                    observer.OnCompleted();
                };

                var untilSubscription = new SerialDisposable();

                var schedule = Scheduler.Immediate.Schedule(
                    self =>
                {
                    if (!source.AtEndOfSequence &&
                        (untilCount == unlimitedCount || matchCount < untilCount))
                    {
                        if (untilParser == null)
                        {
                            iterate(self);
                        }
                        else
                        {
                            untilSubscription.SetDisposableIndirectly(() =>
                                                                      untilParser.Parse(source).Any().Subscribe(
                                                                          any =>
                            {
                                if (!any)
                                {
                                    iterate(self);
                                }
                                else
                                {
                                    complete();
                                }
                            },
                                                                          observer.OnError));
                        }
                    }
                    else
                    {
                        complete();
                    }
                });

                return new CompositeDisposable(schedule, untilSubscription);
            }));
        }
Example #24
0
        private static IObservable <IParseResult <IObservable <TSource> > > AmbiguousGroupInternal <TSource>(
            IObservableCursor <TSource> source,
            IObservableParser <TSource, TSource> open,
            IObservableParser <TSource, TSource> close)
        {
            Contract.Requires(source != null);
            Contract.Requires(open != null);
            Contract.Requires(close != null);
            Contract.Ensures(Contract.Result <IObservable <IParseResult <IObservable <TSource> > > >() != null);

            return(Observable.Create <IParseResult <IObservable <TSource> > >(
                       observer =>
            {
                var branch = source.Branch();

                var disposables = new CompositeDisposable(branch);

                bool hasOpenResult = false;

                disposables.Add(open.Parse(source).SubscribeSafe(
                                    openResult =>
                {
                    hasOpenResult = true;

                    int openCount = 1;

                    var openSinks = new List <Action <IParseResult <TSource> > >();
                    var closeSinks = new List <Action <IParseResult <TSource> > >();
                    var contentSinks = new List <Action <IParseResult <TSource> > >();
                    var bufferedResults = new List <IEnumerable <IParseResult <IObservable <TSource> > > >();

                    Func <List <IParseResult <IObservable <TSource> > > > addBuffer = () =>
                    {
                        var buffer = new List <IParseResult <IObservable <TSource> > >();
                        bufferedResults.Add(buffer);
                        return buffer;
                    };

                    Action installSinks = () =>
                    {
                        var buffer = addBuffer();
                        var content = new List <TSource>();

                        openSinks.Add(result => content.Add(result.Value));
                        contentSinks.Add(result => content.Add(result.Value));
                        closeSinks.Add(result =>
                        {
                            // copy the content list to create a new branch
                            var branchResult = result.Yield(new List <TSource>(content).ToObservable(Scheduler.Immediate));

                            buffer.Add(branchResult);

                            if (openCount > 0)
                            {
                                content.Add(result.Value);
                            }
                        });
                    };

                    // base sinks must be installed first - openCount must be incremented before other sinks are executed
                    openSinks.Add(_ => { openCount++; installSinks(); });
                    closeSinks.Add(_ => { openCount--; });

                    // now we can install the sinks for the first open (matched in the foreach above)
                    installSinks();

                    var innerBranch = branch.Remainder(openResult.Length);

                    bool hasInnerResult = false;
                    IObservableParser <TSource, TSource> current = open;

                    var recursion = new SingleAssignmentDisposable();

                    disposables.Add(recursion);

                    recursion.Disposable = Scheduler.Immediate.Schedule(
                        self =>
                    {
                        var capturedBranch = innerBranch;

                        var innerParser =
                            open.OnSuccess(innerOpenResult =>
                        {
                            hasInnerResult = true;

                            var clone = openSinks.ToList();

                            // the sinks list is modified when open is matched, so we must run a clone
                            clone.ForEach(sink => sink(innerOpenResult));

                            innerBranch = capturedBranch.Remainder(innerOpenResult.Length);

                            current = open;
                        })
                            .Or(
                                close.OnSuccess(closeResult =>
                        {
                            hasInnerResult = true;

                            closeSinks.ForEach(sink => sink(closeResult));

                            innerBranch = capturedBranch.Remainder(closeResult.Length);

                            current = close;
                        }))
                            .Or(
                                current.Next.OnSuccess(content =>
                        {
                            hasInnerResult = true;

                            contentSinks.ForEach(sink => sink(content));

                            innerBranch = capturedBranch.Remainder(content.Length);
                        }));

                        var innerSubscription = new SingleAssignmentDisposable();

                        disposables.Add(innerSubscription);

                        innerSubscription.Disposable = innerParser.Parse(capturedBranch).SubscribeSafe(
                            _ => { },
                            observer.OnError,
                            () =>
                        {
                            if (openCount > 0 && hasInnerResult)
                            {
                                self();
                            }
                            else
                            {
                                innerBranch.Dispose();

                                disposables.Remove(innerSubscription);
                                disposables.Remove(recursion);

                                if (hasInnerResult)
                                {
                                    try
                                    {
                                        bufferedResults.Concat().ForEach(observer.OnNext);
                                    }
                                    catch (Exception ex)
                                    {
                                        observer.OnError(ex);
                                    }

                                    observer.OnCompleted();
                                }
                                else
                                {
                                    // completing without results is failure
                                    observer.OnCompleted();
                                }
                            }
                        });
                    });
                },
                                    observer.OnError,
                                    () =>
                {
                    if (!hasOpenResult)
                    {
                        observer.OnCompleted();
                    }
                }));

                return disposables;
            }));
        }
Example #25
0
 public IObservable <IParseResult <TResult> > Parse(IObservableCursor <byte> source)
 {
     return(null);
 }