/// <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); })); } }
/// <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(); }); })); }
/// <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>())); }
/// <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> /// 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))); }
/// <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> /// <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> /// <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, IObservable <TResult> > AtEndOfSequence <TSource, TResult>( this IObservableParser <TSource, TResult> parser) { Contract.Requires(parser != null); Contract.Ensures(Contract.Result <IObservableParser <TSource, IObservable <TResult> > >() != null); return(parser.Yield <TSource, TResult, IObservable <TResult> >( "AtEndOfSequence", (source, observer) => { IDisposable disposable; if (source.IsSequenceTerminated) { if (source.AtEndOfSequence) { observer.OnNext(ObservableParseResult.SuccessMany <TResult>(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(ObservableParseResult.SuccessMany <TResult>(length: 0)); } observer.OnCompleted(); }), count: 1); } return disposable; })); }
/// <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()); } }