public IMultiResult <TOutput> Parse(IParseState <TInput> state) { var multiResult = _inner.Parse(state); var results = new List <IResultAlternative <TOutput> >(); foreach (var alt in multiResult.Results.Where(r => r.Success)) { alt.Continuation.Rewind(); _left.Location = multiResult.Location; _left.Value = alt.Value; var result = _right.Parse(state); if (!result.Success) { results.Add(new FailureResultAlternative <TOutput>("Right parser returned no valid results", multiResult.StartCheckpoint)); continue; } foreach (var resultAlt in result.Results) { results.Add(new SuccessResultAlternative <TOutput>(resultAlt.Value, resultAlt.Consumed, resultAlt.Continuation)); } } multiResult.StartCheckpoint.Rewind(); return(new MultiResult <TOutput>(this, multiResult.Location, multiResult.StartCheckpoint, results)); }
/// <summary> /// Execute a parser and catch any unhandled exceptions which may be thrown by it. On /// receiving an exception, the input sequence is rewound to the location where Try started /// and options are provided to determine what actions to take. /// </summary> /// <typeparam name="TOutput"></typeparam> /// <param name="parser"></param> /// <param name="examine"></param> /// <param name="bubble"></param> /// <returns></returns> public static IMultiParser <TInput, TOutput> Try <TOutput>(IMultiParser <TInput, TOutput> parser, Action <Exception>?examine = null, bool bubble = false) => new Function <TInput, TOutput> .MultiParser(args => { var cp = args.Input.Checkpoint(); try { return(parser.Parse(args.State)); } catch (ControlFlowException) { // These exceptions are used within the library for non-local control flow, and // should not be caught or modified here. throw; } catch (Exception e) { cp.Rewind(); examine?.Invoke(e); if (bubble) { throw; } return(new MultiResult <TOutput>(parser, cp.Location, cp, Array.Empty <IResultAlternative <TOutput> >(), data: new[] { e })); } }, "TRY {child}", new[] { parser });
/// <summary> /// Attempts a parse but does not consume any input. Instead it returns a boolean true if /// the parser would succeed or false otherwise. /// </summary> /// <typeparam name="TInput"></typeparam> /// <param name="parser"></param> /// <param name="input"></param> /// <returns></returns> public static bool CanMatch <TInput>(this IMultiParser <TInput> parser, ISequence <TInput> input) { var state = new ParseState <TInput>(input, Defaults.LogMethod); var result = parser.Parse(state); result.StartCheckpoint.Rewind(); return(result.Success); }
/// <summary> /// Convenience method for parsers which act on character sequences. Attempts a parse but /// does not consume any input. Returns true if the parse would succeed, false otherwise. /// </summary> /// <param name="parser"></param> /// <param name="input"></param> /// <param name="options"></param> /// <returns></returns> public static bool CanMatch(this IMultiParser <char> parser, string input, StringCharacterSequence.Options options = default) { // Don't need to .Checkpoint()/.Rewind() because the sequence is private and we don't // reuse it var sequence = new StringCharacterSequence(input, options); var state = new ParseState <char>(sequence, Defaults.LogMethod); var result = parser.Parse(state); return(result.Success); }
public static IMultiParser <TInput, TOutput> Context <TOutput>(IMultiParser <TInput, TOutput> parser, Action <IParseState <TInput> > setup, Action <IParseState <TInput> > cleanup) => new Function <TInput, TOutput> .MultiParser(args => { var state = args.State; try { setup(state); return(parser.Parse(state)); } finally { cleanup(state); } }, string.Empty, new[] { parser });
public IMultiResult <TOutput> Parse(IParseState <TInput> state) => _value.Parse(state);
/// <summary> /// Convenience method to invoke a parser which does not return a value. Creates the /// necessary ParseState. /// </summary> /// <typeparam name="TInput"></typeparam> /// <param name="parser"></param> /// <param name="input"></param> /// <param name="log"></param> /// <returns></returns> public static IMultiResult Parse <TInput>(this IMultiParser <TInput> parser, ISequence <TInput> input, Action <string>?log = null) => parser.Parse(new ParseState <TInput>(input, log ?? Defaults.LogMethod));