/// <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 });
Ejemplo n.º 2
0
    /// <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>
 /// Expect the IMultiResult to contain exactly 1 alternative, and select that to continue.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <returns></returns>
 public static IParser <TInput, TOutput> Single <TInput, TOutput>(this IMultiParser <TInput, TOutput> multiParser)
 => multiParser.Select(args =>
 {
     if (args.Result.Results.Count == 1)
     {
         return(args.Success(args.Result.Results[0]));
     }
     return(args.Failure());
 });
 /// <summary>
 /// Returns the first successful alternative which matches a predicate to continue the
 /// parse with.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <param name="predicate"></param>
 /// <returns></returns>
 public static IParser <TInput, TOutput> First <TInput, TOutput>(this IMultiParser <TInput, TOutput> multiParser, Func <IResultAlternative <TOutput>, bool> predicate)
 {
     Assert.ArgumentNotNull(predicate, nameof(predicate));
     return(multiParser.Select(args =>
     {
         var selected = args.Result.Results.FirstOrDefault(predicate);
         return selected != null ? args.Success(selected) : args.Failure();
     }));
 }
 /// <summary>
 /// Select the result alternative which consumed the most amount of input and use that to
 /// continue the parse. If there are no alternatives, returns failure. If there are ties,
 /// the first is selected.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <returns></returns>
 public static IParser <TInput, TOutput> Longest <TInput, TOutput>(this IMultiParser <TInput, TOutput> multiParser)
 => multiParser.Select(args =>
 {
     var longest = args.Result.Results
                   .Where(r => r.Success)
                   .OrderByDescending(r => r.Consumed)
                   .FirstOrDefault();
     return(longest != null ? args.Success(longest) : args.Failure());
 });
Ejemplo n.º 6
0
    /// <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);
    }
Ejemplo n.º 7
0
        public SingleReplaceResult SetParser(IParser parser)
        {
            var previous = _value;

            if (parser is IMultiParser <TInput, TOutput> typed)
            {
                _value = typed;
            }
            return(new SingleReplaceResult(this, previous, _value));
        }
Ejemplo n.º 8
0
 public MultiParser(IMultiParser <TInput, TMiddle> inner, Func <IParser <TInput, TMiddle>, IMultiParser <TInput, TOutput> > getParser, string name = "")
 {
     Assert.ArgumentNotNull(inner, nameof(inner));
     Assert.ArgumentNotNull(getParser, nameof(getParser));
     _inner     = inner;
     _left      = new LeftValue(name);
     _right     = getParser(_left);
     _getParser = getParser;
     Name       = name;
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Creates a new contextual data frame to store data if the data store supports frames.
 /// Execute the inner parser. When the inner parser concludes, pop the data frame off the
 /// data store.
 /// </summary>
 /// <typeparam name="TOutput"></typeparam>
 /// <typeparam name="TData"></typeparam>
 /// <param name="inner"></param>
 /// <param name="values"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> DataContext <TOutput, TData>(IMultiParser <TInput, TOutput> inner, Dictionary <string, TData> values)
 => Context(inner,
            state =>
 {
     (state.Data as CascadingKeyValueStore)?.PushFrame();
     foreach (var value in values)
     {
         state.Data.Set(value.Key, value.Value);
     }
 },
            state => (state.Data as CascadingKeyValueStore)?.PopFrame()
            );
Ejemplo n.º 10
0
 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 });
Ejemplo n.º 11
0
 /// <summary>
 /// Parse a string using the given character multiparser.
 /// </summary>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="p"></param>
 /// <param name="s"></param>
 /// <returns></returns>
 public static IMultiResult <TOutput> Parse <TOutput>(this IMultiParser <char, TOutput> p, string s)
 => p.Parse(new ParseState <char>(new StringCharacterSequence(s, default), Defaults.LogMethod));
 /// <summary>
 /// Transform one multi result into another multi result. Allows modifying the result
 /// values and all result metadata.
 /// </summary>
 /// <typeparam name="TMiddle"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="parser"></param>
 /// <param name="transform"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> TransformResultMulti <TMiddle, TOutput>(IMultiParser <TInput, TMiddle> parser, Func <Transform <TInput, TMiddle, TOutput> .MultiArguments, IMultiResult <TOutput> > transform)
 => new Transform <TInput, TMiddle, TOutput> .MultiParser(parser, transform);
Ejemplo n.º 13
0
 /// <summary>
 /// Push a recursive data frame before executing the given parser, and then pop the data
 /// frame when the parser completes.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <typeparam name="TData"></typeparam>
 /// <param name="p"></param>
 /// <param name="name"></param>
 /// <param name="value"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> WithDataContext <TInput, TOutput, TData>(this IMultiParser <TInput, TOutput> p, string name, TData value)
     where TData : notnull
 => ParserMethods <TInput> .DataContext(p, name, value);
Ejemplo n.º 14
0
 /// <summary>
 /// Push a recursive data frame before executing the given parser, and then pop the data
 /// frame when the parser completes.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="p"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> WithDataContext <TInput, TOutput>(this IMultiParser <TInput, TOutput> p)
 => ParserMethods <TInput> .DataContext(p);
 /// <summary>
 /// Transforms the output value of the parser.
 /// </summary>
 /// <typeparam name="TMiddle"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="parser"></param>
 /// <param name="transform"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Transform <TMiddle, TOutput>(IMultiParser <TInput, TMiddle> parser, Func <TMiddle, TOutput> transform)
 => TransformResultMulti <TMiddle, TOutput>(parser, args => args.Result.Transform(transform));
Ejemplo n.º 16
0
 /// <summary>
 /// Creates a new contextual data frame to store data if the data store supports frames.
 /// Execute the inner parser. When the inner parser concludes, pop the data frame off the
 /// data store.
 /// </summary>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="inner"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> DataContext <TOutput>(IMultiParser <TInput, TOutput> inner)
 => Context(inner,
            state => (state.Data as CascadingKeyValueStore)?.PushFrame(),
            state => (state.Data as CascadingKeyValueStore)?.PopFrame()
            );
Ejemplo n.º 17
0
 /// <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));
 /// <summary>
 /// Invoke a special callback to attempt to select a single alternative and turn it into
 /// an IResult.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiparser"></param>
 /// <param name="select"></param>
 /// <returns></returns>
 public static IParser <TInput, TOutput> Select <TInput, TOutput>(this IMultiParser <TInput, TOutput> multiparser, Func <Select <TInput, TOutput> .Arguments, IOption <IResultAlternative <TOutput> > > select)
 => new Select <TInput, TOutput> .Parser(multiparser, select);
Ejemplo n.º 19
0
 /// <summary>
 /// Make this parser replaceable.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="p"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Replaceable <TInput, TOutput>(this IMultiParser <TInput, TOutput> p)
 => ParserMethods <TInput> .Replaceable(p);
Ejemplo n.º 20
0
 /// <summary>
 /// Make this parser replaceable. Gives the parser a name so that it can be easily found
 /// and replaced.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="p"></param>
 /// <param name="name"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Replaceable <TInput, TOutput>(this IMultiParser <TInput, TOutput> p, string name)
 => ParserMethods <TInput> .Replaceable(p).Named(name);
 /// <summary>
 /// Selects the first successful alternative to continue the parse with.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <returns></returns>
 public static IParser <TInput, TOutput> First <TInput, TOutput>(this IMultiParser <TInput, TOutput> multiParser)
 => First(multiParser, r => r.Success);
Ejemplo n.º 22
0
 /// <summary>
 /// Continue the parse with each alternative separately.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TMiddle"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <param name="getParser"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> ContinueWith <TInput, TMiddle, TOutput>(this IMultiParser <TInput, TMiddle> multiParser, Func <IParser <TInput, TMiddle>, IMultiParser <TInput, TOutput> > getParser)
 => new ContinueWith <TInput, TMiddle, TOutput> .MultiParser(multiParser, getParser);
Ejemplo n.º 23
0
 public MultiParser(IMultiParser <TInput, TOutput> defaultValue, string name = "")
 {
     Assert.ArgumentNotNull(defaultValue, nameof(defaultValue));
     _value = defaultValue;
     Name   = name;
 }
Ejemplo n.º 24
0
 /// <summary>
 /// Continue the parse with all the given parsers.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TMiddle"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="parser"></param>
 /// <param name="getParsers"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> ContinueWithEach <TInput, TMiddle, TOutput>(this IMultiParser <TInput, TMiddle> parser, Func <IParser <TInput, TMiddle>, IEnumerable <IParser <TInput, TOutput> > > getParsers)
 => ContinueWith(parser, left => new EachParser <TInput, TOutput>(getParsers(left).ToArray()));
Ejemplo n.º 25
0
 /// <summary>
 /// Transform the values of all result alternatives.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TMiddle"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <param name="transform"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Transform <TInput, TMiddle, TOutput>(this IMultiParser <TInput, TMiddle> multiParser, Func <TMiddle, TOutput> transform)
 => ParserMethods <TInput> .Transform(multiParser, transform);
Ejemplo n.º 26
0
 /// <summary>
 /// Transform the values of all result alternatives.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TMiddle"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="multiParser"></param>
 /// <param name="transform"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Transform <TInput, TMiddle, TOutput>(this IMultiParser <TInput, TMiddle> multiParser, Func <Transform <TInput, TMiddle, TOutput> .MultiArguments, IMultiResult <TOutput> > transform)
 => ParserMethods <TInput> .TransformResultMulti(multiParser, transform);
Ejemplo n.º 27
0
 /// <summary>
 /// Creates a new contextual data frame to store data if the data store supports frames.
 /// Execute the inner parser. When the inner parser concludes, pop the data frame off the
 /// data store.
 /// </summary>
 /// <typeparam name="TOutput"></typeparam>
 /// <typeparam name="TData"></typeparam>
 /// <param name="inner"></param>
 /// <param name="name"></param>
 /// <param name="value"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> DataContext <TOutput, TData>(IMultiParser <TInput, TOutput> inner, string name, TData value)
     where TData : notnull
 => DataContext(inner, new Dictionary <string, object> {
Ejemplo n.º 28
0
 /// <summary>
 /// Push a recursive data frame before executing the given parser, and then pop the data
 /// frame when the parser completes.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <typeparam name="TData"></typeparam>
 /// <param name="p"></param>
 /// <param name="values"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> WithDataContext <TInput, TOutput, TData>(this IMultiParser <TInput, TOutput> p, Dictionary <string, TData> values)
 => ParserMethods <TInput> .DataContext(p, values);
Ejemplo n.º 29
0
 /// <summary>
 /// Cache result values of this parser so on the next call to Parse from the same location
 /// an existing result value can be used.
 /// </summary>
 /// <typeparam name="TInput"></typeparam>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="p"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Cache <TInput, TOutput>(this IMultiParser <TInput, TOutput> p)
 => ParserMethods <TInput> .Cache(p);
 /// <summary>
 /// Serves as a placeholder in the parser tree where an in-place replacement can be made.
 /// </summary>
 /// <typeparam name="TOutput"></typeparam>
 /// <param name="defaultParser"></param>
 /// <returns></returns>
 public static IMultiParser <TInput, TOutput> Replaceable <TOutput>(IMultiParser <TInput, TOutput> defaultParser)
 => new Replaceable <TInput, TOutput> .MultiParser(defaultParser ?? new FailParser <TInput, TOutput>());