Beispiel #1
0
        /// <summary>
        /// Matches the specified <paramref name="parser"/> or yields the specified default result if there are
        /// no matches.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser that might produce matches.</param>
        /// <param name="defaultResult">The value that is yielded if the specified <paramref name="parser"/> does not match.</param>
        /// <returns>A parser that yields matches from the specified <paramref name="parser"/> or the specified default result
        /// if the <paramref name="parser"/> does not match.</returns>
        public static IObservableParser <TSource, TResult> WithDefault <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser,
            TResult defaultResult)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield(
                       "WithDefault",
                       (source, observer) =>
            {
                bool hasResult = false;

                return parser.Parse(source).SubscribeSafe(
                    result =>
                {
                    hasResult = true;

                    observer.OnNext(result);
                },
                    observer.OnError,
                    () =>
                {
                    if (!hasResult)
                    {
                        observer.OnNext(ParseResult.Create(defaultResult, length: 0));
                    }

                    observer.OnCompleted();
                });
            }));
        }
Beispiel #2
0
        /// <summary>
        /// Matches the specified <paramref name="parser"/> or yields success without a value when it does not match.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements of the result sequences that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser that might produce matches.</param>
        /// <returns>A parser that yields matches from the specified <paramref name="parser"/> or
        /// an empty observable sequence to indicate success when it does not match.</returns>
        public static IObservableParser <TSource, IObservable <TResult> > Maybe <TSource, TResult>(
            this IObservableParser <TSource, IObservable <TResult> > parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null);

            return(parser.Yield(
                       "Maybe",
                       (source, observer) =>
            {
                bool hasResult = false;

                return parser.Parse(source).SubscribeSafe(
                    result =>
                {
                    hasResult = true;

                    observer.OnNext(result);
                },
                    observer.OnError,
                    () =>
                {
                    if (!hasResult)
                    {
                        observer.OnNext(ObservableParseResult.SuccessMany <TResult>(length: 0));
                    }

                    observer.OnCompleted();
                });
            }));
        }
Beispiel #3
0
        /// <summary>
        /// Yields success when the specified <paramref name="parser"/> does not match.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser for which any match results in failure.</param>
        /// <returns>A parser that yields failure when the specified <paramref name="parser"/> matches or
        /// an empty sequence to indicate success when it does not match.</returns>
        public static IObservableParser <TSource, IObservable <TResult> > None <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null);

            if (parser is IObservableParserCursor <TSource> )
            {
                return(parser.AtEndOfSequence());
            }
            else
            {
                return(parser.Yield <TSource, TResult, IObservable <TResult> >(
                           "None",
                           (source, observer) =>
                {
                    return parser.Parse(source).Any().SubscribeSafe(
                        any =>
                    {
                        if (!any)
                        {
                            observer.OnNext(ObservableParseResult.SuccessMany <TResult>(length: 0));
                        }
                    },
                        observer.OnError,
                        observer.OnCompleted);
                }));
            }
        }
Beispiel #4
0
        /// <summary>
        /// Indicates a successful parse operation without actually parsing by yielding a single result containing an empty sequence.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements in the sequences that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser for which a single empty result sequence is returned to indicate success.</param>
        /// <remarks>
        /// <see cref="Success{TSource,TResult}(IObservableParser{TSource,IObservable{TResult}})"/> is required as an explicit overload
        /// because the meaning of the parser's result sequence is special and must not be compounded into a sequence of sequences,
        /// which would happen if the <see cref="Success{TSource,TResult}(IObservableParser{TSource,TResult})"/> overload were to be called
        /// instead.
        /// </remarks>
        /// <returns>A parser that returns a single result containing an empty sequence with a length
        /// of zero, starting from the index at which the specified <paramref name="parser"/> starts.</returns>
        public static IObservableParser <TSource, IObservable <TResult> > Success <TSource, TResult>(
            this IObservableParser <TSource, IObservable <TResult> > parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null);

            return(parser.Yield("Success", source => ObservableParseResult.ReturnSuccessMany <TResult>(length: 0)));
        }
        /// <summary>
        /// Converts greedy matches from the specified <paramref name="parser"/> into matches that
        /// have a length of zero.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The greedy parser to be made into a non-greedy parser.</param>
        /// <returns>A parser that converts the greedy matches from the specified <paramref name="parser"/> into
        /// matches that have a length of zero.</returns>
        public static IObservableParser <TSource, TResult> NonGreedy <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("NonGreedy", source => parser.Parse(source).Select(result => result.Yield(length: 0))));
        }
        /// <summary>
        /// Projects each match from the specified <paramref name="parser"/> into a singleton observable sequence
        /// that contains the match's value.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser from which matches will be projected into singleton observable sequences.</param>
        /// <returns>A parser that yields matches from the specified <paramref name="parser"/> projected into singleton
        /// observable sequences.</returns>
        public static IObservableParser <TSource, IObservable <TResult> > Amplify <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null);

            return(parser.Yield("Amplify", source => parser.Parse(source).Select(result => result.YieldMany())));
        }
Beispiel #7
0
        /// <summary>
        /// Indicates a failure to parse without actually parsing by returning an empty sequence of parse results.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser that is to fail.</param>
        /// <returns>A parser that always returns an empty sequence of parse results, starting from the index at which
        /// the specified <paramref name="parser"/> starts.</returns>
        public static IObservableParser <TSource, TResult> Failure <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("Failure", source => ObservableParseResult.ReturnFailure <TResult>()));
        }
Beispiel #8
0
        /// <summary>
        /// Invokes the specified <paramref name="action"/> on each result for its side-effects.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser from which results will be supplied to the specified <paramref name="action"/>.</param>
        /// <param name="action">The method that will be called for each parser result.</param>
        /// <returns>A new parser that is the same as the specified parser and also invokes the specified
        /// <paramref name="action"/> with each result for its side-effects.</returns>
        public static IObservableParser <TSource, TResult> OnSuccess <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser,
            Action <IParseResult <TResult> > action)
        {
            Contract.Requires(parser != null);
            Contract.Requires(action != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("OnSuccess", source => parser.Parse(source).Do(action)));
        }
Beispiel #9
0
        /// <summary>
        /// Projects matches from the specified <paramref name="parser"/> into a new form.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TIntermediate">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are projected from the matches of the specified <paramref name="parser"/>.</typeparam>
        /// <param name="parser">The parser from which matches will be projected by the specified <paramref name="selector"/> function.</param>
        /// <param name="selector">A transform function to apply to each match.</param>
        /// <returns>A parser that projects matches from the specified <paramref name="parser"/> into a new form.</returns>
        public static IObservableParser <TSource, TResult> Select <TSource, TIntermediate, TResult>(
            this IObservableParser <TSource, TIntermediate> parser,
            Func <TIntermediate, TResult> selector)
        {
            Contract.Requires(parser != null);
            Contract.Requires(selector != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("Select", source => parser.Parse(source).Select(result => result.Yield(selector))));
        }
Beispiel #10
0
        /// <summary>
        /// Matches everything in between the specified <paramref name="open"/> and <paramref name="close"/> parsers,
        /// yielding the first unambiguous match as well as everything in between any sub-groups and overlapping groups,
        /// extending past the unambiguous match of the <paramref name="close"/> parser, that match the same grammar.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <param name="open">The parser after which the group begins.</param>
        /// <param name="close">The parser at which the group ends.</param>
        /// <remarks>
        /// The same <paramref name="open"/> or <paramref name="close"/> parser may produce multiple matches at the same index.
        /// </remarks>
        /// <returns>A parser with a grammar that matches the <paramref name="open"/> parser, followed by everything up to the first
        /// match of the <paramref name="close"/> parser, yielding the results in between as well as the results of all ambiguous
        /// matches of the group grammar.</returns>
        public static IObservableParser <TSource, IObservable <TSource> > AmbiguousGroup <TSource>(
            this IObservableParser <TSource, TSource> open,
            IObservableParser <TSource, TSource> close)
        {
            Contract.Requires(open != null);
            Contract.Requires(close != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TSource> > >() != null);

            return(open.Yield("AmbiguousGroup", source => AmbiguousGroupInternal(source, open, close)));
        }
Beispiel #11
0
        /// <summary>
        /// Matches all results from the specified <paramref name="parser"/> for which the specified
        /// <paramref name="predicate"/> returns <see langword="true"/>.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser from which matches will be filtered by the specified <paramref name="predicate"/>.</param>
        /// <param name="predicate">A function that returns <see langword="true"/> to indicate when a match should be yielded and
        /// <see langword="false"/> when a match should be ignored.</param>
        /// <returns>A parser that matches only those results from the specified <paramref name="parser"/> for which
        /// the specified <paramref name="predicate"/> returns <see langword="true"/>.</returns>
        public static IObservableParser <TSource, TResult> Where <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser,
            Func <TResult, bool> predicate)
        {
            Contract.Requires(parser != null);
            Contract.Requires(predicate != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("Where", source => parser.Parse(source).Where(result => predicate(result.Value))));
        }
Beispiel #12
0
        /// <summary>
        /// Indicates a successful parse operation without actually parsing by yielding the specified scalar <paramref name="result"/>
        /// with the specified length.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TIntermediate">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the <paramref name="result"/>.</typeparam>
        /// <param name="parser">The parser for which the specified <paramref name="result"/> indicates success.</param>
        /// <param name="result">The value of the created parser's result.</param>
        /// <param name="length">The length of the created parser's result.</param>
        /// <returns>A parser that always returns the specified scalar <paramref name="result"/> with the specified
        /// length, starting from the index at which the specified <paramref name="parser"/> starts.</returns>
        public static IObservableParser <TSource, TResult> Success <TSource, TIntermediate, TResult>(
            this IObservableParser <TSource, TIntermediate> parser,
            TResult result,
            int length)
        {
            Contract.Requires(parser != null);
            Contract.Requires(length >= 0);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("Success", source => ObservableParseResult.Return(result, length)));
        }
Beispiel #13
0
        /// <summary>
        /// Projects each match from the specified <paramref name="parser"/> into another parser, merges all of the results
        /// and transforms them with the result selector function.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TFirstResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <typeparam name="TSecondResult">The type of the elements that are generated from the projected parsers.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are projected from the matches of the projected parsers.</typeparam>
        /// <param name="parser">The parser from which each match is passed to the specified parser selector function to create
        /// the next parser.</param>
        /// <param name="parserSelector">A transform function to apply to each match from the first <paramref name="parser"/>.</param>
        /// <param name="resultSelector">A transform function to apply to each match from the projected parsers.</param>
        /// <returns>A parser that projects each match from the specified <paramref name="parser"/> into another parser,
        /// merges all of the results and transforms them with the result selector function.</returns>
        public static IObservableParser <TSource, TResult> SelectMany <TSource, TFirstResult, TSecondResult, TResult>(
            this IObservableParser <TSource, TFirstResult> parser,
            Func <TFirstResult, IObservableParser <TSource, TSecondResult> > parserSelector,
            Func <TFirstResult, TSecondResult, TResult> resultSelector)
        {
            Contract.Requires(parser != null);
            Contract.Requires(parserSelector != null);
            Contract.Requires(resultSelector != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("SelectMany", source => SelectManyInternal(source, parser, parserSelector, resultSelector)));
        }
Beispiel #14
0
        /// <summary>
        /// Throws a <see cref="ParseException"/> returned by the specified function if the specified
        /// <paramref name="parser"/> does not match.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser that must succeed otherwise a <see cref="ParseException"/> is thrown.</param>
        /// <param name="exceptionFactory">A function that returns the <see cref="ParseException"/> to be thrown describing the
        /// failed expectation.</param>
        /// <returns>A parser that yields the matches from the specified <paramref name="parser"/> or throws
        /// a <see cref="ParseException"/> returned by the specified functions if there are no matches.</returns>
        public static IObservableParser <TSource, TResult> Required <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser,
            Func <int, Exception> exceptionFactory)
        {
            Contract.Requires(parser != null);
            Contract.Requires(exceptionFactory != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield(
                       "Required",
                       (source, observer) =>
            {
                int index = source.CurrentIndex;

                bool hasResult = false;

                return parser.Parse(source).SubscribeSafe(
                    result =>
                {
                    hasResult = true;

                    observer.OnNext(result);
                },
                    observer.OnError,
                    () =>
                {
                    if (hasResult)
                    {
                        observer.OnCompleted();
                    }
                    else
                    {
                        Exception exception = exceptionFactory(index);

                        if (exception == null)
                        {
                            exception = new ParseException(index);
                        }
                        else if (!(exception is ParseException))
                        {
                            exception = new ParseException(index, exception);
                        }

#if !SILVERLIGHT && !PORT_45 && !PORT_40
                        ParserTraceSources.Input.TraceEvent(System.Diagnostics.TraceEventType.Error, 0, "{0}", exception);
#endif

                        observer.OnError(exception);
                    }
                });
            }));
        }
Beispiel #15
0
        /// <summary>
        /// Projects each match from the specified <paramref name="parser"/> into an observable sequence, merges all of the results
        /// and transforms them with the result selector function.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TFirstResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <typeparam name="TCollection">The type of the elements in the sequences that are projected from the matches.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are projected from the projected sequences.</typeparam>
        /// <param name="parser">The parser from which each match is passed to the specified collection selector function.</param>
        /// <param name="collectionSelector">A transform function to apply to each match from the first <paramref name="parser"/>.</param>
        /// <param name="resultSelector">A transform function to apply to each element from the projected sequences.</param>
        /// <param name="lengthSelector">A function that returns the length for each pair of projected values.</param>
        /// <returns>A parser that projects each match from the specified <paramref name="parser"/> into an observable sequence,
        /// merges all of the results and transforms them with the result selector function.</returns>
        public static IObservableParser <TSource, TResult> SelectMany <TSource, TFirstResult, TCollection, TResult>(
            this IObservableParser <TSource, TFirstResult> parser,
            Func <TFirstResult, IObservable <TCollection> > collectionSelector,
            Func <TFirstResult, TCollection, TResult> resultSelector,
            Func <IParseResult <TFirstResult>, TCollection, int> lengthSelector)
        {
            Contract.Requires(parser != null);
            Contract.Requires(collectionSelector != null);
            Contract.Requires(resultSelector != null);
            Contract.Requires(lengthSelector != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield("SelectMany", source => SelectManyInternal(source, parser, collectionSelector, resultSelector, lengthSelector)));
        }
Beispiel #16
0
        /// <summary>
        /// Yields success if the specified parser starts at the end of the input sequence.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <typeparam name="TSuccess">The type of the success value.</typeparam>
        /// <param name="parser">The parser that provides the context in which to check whether the cursor is at the end of the input sequence.</param>
        /// <param name="successResult">The value that is yielded if the specified parser starts at the end of the input sequence.</param>
        /// <returns>A new parser that yields success without parsing if the cursor is positioned at the end of the input sequence; otherwise, yields no results.</returns>
        public static IObservableParser <TSource, TSuccess> AtEndOfSequence <TSource, TResult, TSuccess>(
            this IObservableParser <TSource, TResult> parser,
            TSuccess successResult)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TSuccess> >() != null);

            return(parser.Yield <TSource, TResult, TSuccess>(
                       "AtEndOfSequence",
                       (source, observer) =>
            {
                IDisposable disposable;

                if (source.IsSequenceTerminated)
                {
                    if (source.AtEndOfSequence)
                    {
                        observer.OnNext(ParseResult.Create(successResult, length: 0));
                    }

                    observer.OnCompleted();

                    disposable = Disposable.Empty;
                }
                else
                {
                    bool hasResult = false;

                    disposable = source.Subscribe(
                        Observer.Create <TSource>(
                            result => hasResult = true,
                            observer.OnError,
                            () =>
                    {
                        if (!hasResult)
                        {
                            Contract.Assume(source.AtEndOfSequence);

                            observer.OnNext(ParseResult.Create(successResult, length: 0));
                        }

                        observer.OnCompleted();
                    }),
                        count: 1);
                }

                return disposable;
            }));
        }
Beispiel #17
0
        /// <summary>
        /// Matches the specified <paramref name="parser"/> the specified number of times.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser to be matched.</param>
        /// <param name="count">The specified number of times to match the specified <paramref name="parser"/>.</param>
        /// <returns>A parser that matches the specified <paramref name="parser"/> the specified number of times.</returns>
        public static IObservableParser <TSource, IObservable <TResult> > Exactly <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser,
            int count)
        {
            Contract.Requires(parser != null);
            Contract.Requires(count >= 0);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null);

            if (count == 0)
            {
                return(parser.Yield(_ => ObservableParseResult.ReturnSuccessMany <TResult>(length: 0)));
            }
            else if (count == 1)
            {
                // Profiling has shown this to be about 50% faster than Repeat(parser, 1).All()
                return(parser.Amplify());
            }
            else if (parser is IObservableParserCursor <TSource> )
            {
                /* Profiling has shown this to be exponentially faster in next.Exactly(largeN) queries for Ix.
                 * It hasn't been profiled in Rx, but I'm assuming that for similar reasons as Ix it would prove
                 * to be exponentially faster.  Furthermore, due to the extra plumbing in Rx that's being avoided
                 * by this optimization, it may have even greater gains than Ix.
                 */
                return(parser.Yield <TSource, TResult, IObservable <TResult> >(
                           "Exactly",
                           source =>
                           from list in source.Take(count).ToList()
                           where list.Count == count
                           select ParseResult.Create(list.Cast <TResult>().ToObservable(Scheduler.Immediate), count)));
            }
            else
            {
                return(System.Linq.Enumerable.Repeat(parser, count).All());
            }
        }
Beispiel #18
0
        /// <summary>
        /// Applies an <paramref name="accumulator"/> function over each result sequence from the
        /// specified <paramref name="parser"/> and yields a sequence of accumulated results.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TIntermediate">The type of the elements that are generated from parsing the source elements.</typeparam>
        /// <typeparam name="TAccumulate">The type of the accumulation.</typeparam>
        /// <typeparam name="TResult">The type of the elements that are generated from projecting the accumulation.</typeparam>
        /// <param name="parser">The parser that produces a sequence of result sequences to be aggregated.</param>
        /// <param name="seed">A function that returns the initial value of the accumulation for each parse result.</param>
        /// <param name="accumulator">A function to be invoked on each element of each parse result.</param>
        /// <param name="selector">A function that projects the final aggregation of each parse result.</param>
        /// <returns>A parser that returns the aggregated results.</returns>
        public static IObservableParser <TSource, TResult> Aggregate <TSource, TIntermediate, TAccumulate, TResult>(
            this IObservableParser <TSource, IObservable <TIntermediate> > parser,
            Func <TAccumulate> seed,
            Func <TAccumulate, TIntermediate, TAccumulate> accumulator,
            Func <TAccumulate, TResult> selector)
        {
            Contract.Requires(parser != null);
            Contract.Requires(accumulator != null);
            Contract.Requires(selector != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield(
                       "Aggregate",
                       source =>
                       from result in parser.Parse(source)
                       from acc in result.Value.Aggregate(seed(), accumulator)
                       select result.Yield(selector(acc))));
        }
Beispiel #19
0
        public static IObservableParser <TSource, TResult> OnFailure <TSource, TResult>(
            this IObservableParser <TSource, TResult> parser,
            Action action)
        {
            Contract.Requires(parser != null);
            Contract.Requires(action != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield(
                       "OnFailure",
                       (source, observer) =>
            {
                bool hasResult = false;

                return parser.Parse(source).Subscribe(
                    result =>
                {
                    hasResult = true;

                    observer.OnNext(result);
                },
                    observer.OnError,
                    () =>
                {
                    if (!hasResult)
                    {
                        try
                        {
                            action();
                        }
                        catch (Exception ex)
                        {
                            observer.OnError(ex);
                            return;
                        }
                    }

                    observer.OnCompleted();
                });
            }));
        }
        /// <summary>
        /// Matches the single element from the ambiguous result sequence in each match that is yielded by the specified
        /// <paramref name="parser"/> and fails for any match in which there is zero or more than one element.
        /// </summary>
        /// <typeparam name="TSource">The type of the source elements.</typeparam>
        /// <typeparam name="TResult">The type of the elements of the result sequences that are generated from parsing the source elements.</typeparam>
        /// <param name="parser">The parser from which the single result element is yielded for each match.</param>
        /// <returns>A parser that matches the single element from the result sequence of each match that is
        /// yielded by the specified <paramref name="parser"/> and fails for any match in which there is zero
        /// or more than one element.</returns>
        public static IObservableParser <TSource, TResult> Single <TSource, TResult>(
            this IObservableParser <TSource, IObservable <TResult> > parser)
        {
            Contract.Requires(parser != null);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, TResult> >() != null);

            return(parser.Yield <TSource, IObservable <TResult>, TResult>(
                       "Single",
                       source => parser.Parse(source).SelectMany(
                           result => Observable.Create <IParseResult <TResult> >(
                               observer =>
            {
                bool hasResult = false;
                TResult firstResult = default(TResult);

                return result.Value.Take(2).Subscribe(
                    innerResult =>
                {
                    if (!hasResult)
                    {
                        firstResult = innerResult;
                        hasResult = true;
                    }
                    else
                    {
                        hasResult = false;
                    }
                },
                    observer.OnError,
                    () =>
                {
                    if (hasResult)
                    {
                        observer.OnNext(result.Yield(firstResult));
                    }

                    observer.OnCompleted();
                });
            }))));
        }
Beispiel #21
0
        private static IObservableParser <TSource, IObservable <TResult> > AtLeast <TSource, TSeparator, TResult>(
            this IObservableParser <TSource, TResult> parser,
            string name,
            int count,
            int maximum = -1,
            IObservableParser <TSource, TSeparator> separator = null,
            bool nonGreedy = false)
        {
            Contract.Requires(parser != null);
            Contract.Requires(!string.IsNullOrEmpty(name));
            Contract.Requires(count >= 0);
            Contract.Requires(maximum == -1 || maximum >= count);
            Contract.Requires(maximum != 0);
            Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null);

            // TODO: Update this method to properly support multi-result parsers.

            /* The current implementation just uses Math.Max for the lengths and aggregates all of the results into a single list.
             * The correct behavior is more like a SelectMany query, so consider using the new SelectMany overload that AllObservableParser uses.
             */

            /* This method is optimized to prevent stack overflows due to two factors: recursion and using Skip to move the source cursor.
             *
             * The previous implementation used recursive calls to NoneOrMore, in which there was a linear relationship between the number
             * of stack frames and the number of elements in the input sequence.  As an input sequence grew and the parser continued matching
             * elements, the number of calls to the Skip operator (via the Remainder extension) grew linearly, and so did the number of branches
             * due to NoneOrMore using the Or operator, which not only added the Or operator to the stack but added all of the calls to the
             * quantified parser between the stack frames that Or added, for every subsequent element in the sequence that the parser matched.
             */
            return(parser.Yield <TSource, TResult, IObservable <TResult> >(
                       name,
                       (source, observer) =>
            {
                Contract.Requires(source.IsForwardOnly);

                var branch = source.Branch();

                var list = new List <TResult>();

                int total = 0;
                int totalLength = 0;

                Action onCompleted = () =>
                {
                    if (total >= count)
                    {
                        observer.OnNext(new ParseResult <IObservable <TResult> >(list.ToObservable(Scheduler.Immediate), totalLength));
                    }

                    observer.OnCompleted();
                };

                var subscription = new SerialDisposable();

                Func <IDisposable> start = () =>
                                           Scheduler.Immediate.Schedule(self =>
                {
                    bool hasResult = false;
                    bool hasSeparatorResult = false;

                    int length = 0;
                    int separatorLength = 0;

                    Action currentCompleted = () =>
                    {
                        if (hasResult)
                        {
                            totalLength += length + separatorLength;

                            if (total < (maximum == -1 ? count : maximum))
                            {
                                total++;
                            }

                            if (total != maximum && (separator == null || hasSeparatorResult))
                            {
                                if (nonGreedy && total >= count)
                                {
                                    var lookAhead = new LookAheadParseResult <IObservable <TResult> >(list.ToObservable(Scheduler.Immediate), totalLength);

                                    subscription.SetDisposableIndirectly(() => new CompositeDisposable(
                                                                             lookAhead,
                                                                             lookAhead.Subscribe(success =>
                                    {
                                        if (success)
                                        {
                                            onCompleted();
                                        }
                                        else
                                        {
                                            self();
                                        }
                                    })));

                                    observer.OnNext(lookAhead);
                                    return;
                                }
                                else
                                {
                                    self();
                                    return;
                                }
                            }
                        }

                        onCompleted();
                    };

                    subscription.SetDisposableIndirectly(() =>
                                                         parser.Parse(branch).SubscribeSafe(
                                                             result =>
                    {
                        hasResult = true;
                        length = Math.Max(length, result.Length);

                        list.Add(result.Value);
                    },
                                                             observer.OnError,
                                                             () =>
                    {
                        branch.Move(length);

                        if (separator == null)
                        {
                            currentCompleted();
                        }
                        else
                        {
                            subscription.SetDisposableIndirectly(() =>
                                                                 separator.Parse(branch).SubscribeSafe(
                                                                     separatorResult =>
                            {
                                hasSeparatorResult = true;
                                separatorLength = Math.Max(separatorLength, separatorResult.Length);
                            },
                                                                     observer.OnError,
                                                                     () =>
                            {
                                branch.Move(separatorLength);

                                currentCompleted();
                            }));
                        }
                    }));
                });

                if (nonGreedy && count == 0)
                {
                    var startSubscription = new SingleAssignmentDisposable();

                    var lookAhead = new LookAheadParseResult <IObservable <TResult> >(Observable.Empty <TResult>(), length: 0);

                    var lookAheadSubscription = lookAhead.Subscribe(success =>
                    {
                        if (success)
                        {
                            onCompleted();
                        }
                        else
                        {
                            startSubscription.Disposable = start();
                        }
                    });

                    observer.OnNext(lookAhead);

                    return new CompositeDisposable(branch, subscription, lookAhead, lookAheadSubscription, startSubscription);
                }
                else
                {
                    var startSubscription = start();

                    return new CompositeDisposable(branch, subscription, startSubscription);
                }
            }));
        }