/// <summary> /// p1.Or(p2) tries p1, but if it fails without consuming input, runs p2 instead. /// </summary> /// <typeparam name="T">The type of result object generated.</typeparam> /// <param name="p1">The first parser to run.</param> /// <param name="p2">The second parser to run.</param> /// <returns>Returns the combined parser function.</returns> internal static P <TInput, TValue> Or <TInput, TValue>(this P <TInput, TValue> p1, P <TInput, TValue> p2) where TInput : IComparable { return(input => { Consumed <TInput, TValue> consumed1 = p1(input); if (consumed1.ParseResult.Succeeded || consumed1.HasConsumedInput) { return consumed1; } else { Consumed <TInput, TValue> consumed2 = p2(input); if (consumed2.HasConsumedInput) { return consumed2; } return new Consumed <TInput, TValue>( consumed2.HasConsumedInput, consumed2.ParseResult.MergeError(consumed1.ParseResult.ErrorInfo)); } }); }
/// <summary> /// This function runs parser p1 on the input. If it fails, return /// an empty Consumed. If it succeeds, run the provided function on the result /// of the initial function. /// </summary> /// <typeparam name="TValue1">The type of result object generated by the first function.</typeparam> /// <typeparam name="TValue2">The type of result object generated by the second function.</typeparam> /// <param name="p1">The initial parser to run.</param> /// <param name="f">The function defining the second parser to run.</param> /// <returns>Returns the completely constructed parser.</returns> internal static P <TInput, TValue2> Then <TInput, TValue1, TValue2>( this P <TInput, TValue1> p1, Func <TValue1, P <TInput, TValue2> > f) where TInput : IComparable { return(input => { Consumed <TInput, TValue1> consumed1 = p1(input); if (consumed1.ParseResult.Succeeded) { Consumed <TInput, TValue2> consumed2 = f(consumed1.ParseResult.Result)(consumed1.ParseResult.RemainingInput); return new Consumed <TInput, TValue2>( consumed1.HasConsumedInput || consumed2.HasConsumedInput, consumed2.HasConsumedInput ? consumed2.ParseResult : consumed2.ParseResult.MergeError(consumed1.ParseResult.ErrorInfo)); } else { return new Consumed <TInput, TValue2>( consumed1.HasConsumedInput, new ParseResult <TInput, TValue2>(consumed1.ParseResult.ErrorInfo)); } }); }
/// <summary> /// p1.Or(p2) tries p1, but if it fails without consuming input, runs p2 instead. /// </summary> /// <typeparam name="T">The type of result object generated.</typeparam> /// <param name="p1">The first parser to run.</param> /// <param name="p2">The second parser to run.</param> /// <returns>Returns the combined parser function.</returns> internal static P <TokenTuple, T> Or <T>(this P <TokenTuple, T> p1, P <TokenTuple, T> p2) { return(input => { Consumed <TokenTuple, T> consumed1 = p1(input); if (consumed1.ParseResult.Succeeded || consumed1.HasConsumedInput) { return consumed1; } else { Consumed <TokenTuple, T> consumed2 = p2(input); if (consumed2.HasConsumedInput) { return consumed2; } return new Consumed <TokenTuple, T>( consumed2.HasConsumedInput, consumed2.ParseResult.MergeError(consumed1.ParseResult.ErrorInfo)); } }); }
/// <summary> /// If the parse succeeded and consumed input, create a token that indicates /// the result and contains the text and position of the consumed input. /// If the parse was not successful, returns a default TokenTuple /// (TokenType=None). /// </summary> /// <param name="newState">The state after a successful parse.</param> /// <param name="startingState">The state before the parse began.</param> /// <returns>Returns a TokenTuple containing the token type, text and position.</returns> internal static TokenTuple CreateToken(this Consumed <string, TokenType> newState, ParserState <string> startingState) { TokenTuple tok = default(TokenTuple); if ((newState.HasConsumedInput) && (newState.ParseResult.Succeeded)) { tok.TokenType = newState.ParseResult.Result; tok.Position = startingState.Position; tok.Text = ConstructString(newState.InputConsumedSince(startingState)); } return(tok); }
/// <summary> /// Try(p) attempts to run parser p. If it fails, it pretends /// that it hasn't consumed any input. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="p"></param> /// <returns></returns> internal static P <TInput, TValue> Try_ <TInput, TValue>(this P <TInput, TValue> p) { return(input => { Consumed <TInput, TValue> consumed = p(input); if (consumed.HasConsumedInput && !consumed.ParseResult.Succeeded) { return new Consumed <TInput, TValue>(false, consumed.ParseResult); } else { return consumed; } }); }
/// <summary> /// This function runs parser p1 on the input. If it fails, return /// null. If it succeeds, run the provided function on the result /// of the initial function. /// </summary> /// <typeparam name="T">The type of result object generated by the first function.</typeparam> /// <typeparam name="U">The type of result object generated by the second function.</typeparam> /// <param name="p1">The initial parser to run.</param> /// <param name="f">The function defining the second parser to run.</param> /// <returns>Returns the completely constructed parser.</returns> internal static P <TokenTuple, U> Then <T, U>(this P <TokenTuple, T> p1, Func <T, P <TokenTuple, U> > f) { return(input => { Consumed <TokenTuple, T> consumed1 = p1(input); if (consumed1.ParseResult.Succeeded) { Consumed <TokenTuple, U> consumed2 = f(consumed1.ParseResult.Result)(consumed1.ParseResult.RemainingInput); return new Consumed <TokenTuple, U>( consumed1.HasConsumedInput || consumed2.HasConsumedInput, consumed2.HasConsumedInput ? consumed2.ParseResult : consumed2.ParseResult.MergeError(consumed1.ParseResult.ErrorInfo)); } else { return new Consumed <TokenTuple, U>( consumed1.HasConsumedInput, new ParseResult <TokenTuple, U>(consumed1.ParseResult.ErrorInfo)); } }); }
internal List <TInput> InputConsumedSince(Consumed <TInput, TValue> previousConsumedResult) { return(this.ParseResult.ConsumedInputSince(previousConsumedResult.ParseResult)); }