Пример #1
0
        /// <summary>
        /// Refer to another parser indirectly. This allows circular compile-time dependency between parsers.
        /// </summary>
        /// <typeparam name="TToken"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="reference"></param>
        /// <returns></returns>
        public static Parser <TToken, T> Ref <TToken, T>(Func <Parser <TToken, T> > reference)
        {
            if (reference == null)
            {
                throw new ArgumentNullException(nameof(reference));
            }

            Parser <TToken, T> p = null;

            return((i, n) =>
            {
                if (p == null)
                {
                    p = reference();
                }

                if (i.Memos.ContainsKey(p))
                {
                    throw new ParsingException(i.Memos[p].ToString());
                }

                i.Memos[p] = ParserResult <TToken, T> .Failure(i,
                                                               new string[0],
                                                               "Left recursion in the grammar."
                                                               );

                var result = p(i, n);
                i.Memos[p] = result;
                return result;
            });
        }
Пример #2
0
 internal static Parser <char, T> TryConvert <T>(string str, Func <string, T> converter)
 {
     return((i, n) =>
     {
         try
         {
             return ParserResult <char, T> .Success(i, converter(str));
         }
         catch (FormatException)
         {
             return ParserResult <char, T> .Failure(i, $"Failed to parse {str}");
         }
     });
 }
Пример #3
0
        public ParserResult <TToken, U> IfSuccess <U>(Func <ParserResult <TToken, TValue>, ParserResult <TToken, U> > next)
        {
            if (next == null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            if (this.IsSuccess)
            {
                return(next(this));
            }

            return(ParserResult <TToken, U> .Failure(this.Rest, this.Expected, this.Description));
        }
Пример #4
0
        public static Parser <TToken, T> End <TToken, T>(this Parser <TToken, T> parser)
        {
            if (parser == null)
            {
                throw new ArgumentNullException(nameof(parser));
            }

            return((i, n) => parser(i, n).IfSuccess(s =>
                                                    s.Rest.AtEnd ? s : ParserResult <TToken, T> .Failure(
                                                        s.Rest,
                                                        new[] { "end of input" },
                                                        string.Format("unexpected '{0}'", s.Rest.GetCurrent())
                                                        )
                                                    ));
        }
        public static Parser <ScriptToken, ScriptToken> ScriptToken(Func <int, bool> predicate, string expected)
        {
            return(i =>
            {
                if (i.AtEnd)
                {
                    return ParserResult <ScriptToken, ScriptToken> .Failure(i, new[] { expected }, "Unexpected end of input");
                }

                if (predicate(i.GetCurrent().Tag))
                {
                    return ParserResult <ScriptToken, ScriptToken> .Success(i.Advance(), i.GetCurrent());
                }
                return ParserResult <ScriptToken, ScriptToken> .Failure(i, $"Unexpected {i.GetCurrent()}");
            });
        }
Пример #6
0
        public static Parser <TToken, IEnumerable <T> > Repeat <TToken, T>(
            this Parser <TToken, T> parser,
            int minimumCount,
            int maximumCount
            )
        {
            if (parser == null)
            {
                throw new ArgumentNullException(nameof(parser));
            }

            return((i, net) =>
            {
                var remainder = i;
                var result = new List <T>();

                for (var n = 0; n < maximumCount; ++n)
                {
                    var r = parser(remainder, net);

                    if (!r.IsSuccess && n < minimumCount)
                    {
                        var what = r.Rest.AtEnd
                                                                ? "end of input"
                                                                : r.Rest.GetCurrent().ToString();

                        var msg = $"Unexpected '{what}'";
                        var exp = minimumCount == maximumCount
                                                                ? $"'{string.Join(", ", r.Expected)}' {minimumCount} times, but found {n}"
                                                                : $"'{string.Join(", ", r.Expected)}' between {minimumCount} and {maximumCount} times, but found {n}";

                        return ParserResult <TToken, IEnumerable <T> > .Failure(i, new[] { exp }, msg);
                    }

                    if (!ReferenceEquals(remainder, r.Rest))
                    {
                        result.Add(r.Value);
                    }

                    remainder = r.Rest;
                }

                return ParserResult <TToken, IEnumerable <T> > .Success(remainder, result);
            });
        }
Пример #7
0
        /// <summary>
        /// Succeed if the parsed value matches predicate.
        /// </summary>
        /// <typeparam name="TToken"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parser"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static Parser <TToken, T> Where <TToken, T>(this Parser <TToken, T> parser, Func <T, bool> predicate)
        {
            if (parser == null)
            {
                throw new ArgumentNullException(nameof(parser));
            }
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            return((i, n) => parser(i, n).IfSuccess(s =>
                                                    predicate(s.Value) ? s : ParserResult <TToken, T> .Failure(i,
                                                                                                               new string[0],
                                                                                                               string.Format("Unexpected {0}.", s.Value)
                                                                                                               )
                                                    ));
        }
Пример #8
0
        public static ParserResult <TToken, T> DetermineBestError <TToken, T>(
            ParserResult <TToken, T> firstF,
            ParserResult <TToken, T> secondF
            )
        {
            if (secondF.Rest.Position > firstF.Rest.Position)
            {
                return(secondF);
            }

            if (secondF.Rest.Position == firstF.Rest.Position)
            {
                return(ParserResult <TToken, T> .Failure(
                           firstF.Rest,
                           firstF.Expected.Union(secondF.Expected),
                           firstF.Description
                           ));
            }

            return(firstF);
        }
Пример #9
0
        /// <summary>
        /// Attempt parsing only if the <paramref name="except"/> parser fails.
        /// </summary>
        /// <typeparam name="TToken"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="U"></typeparam>
        /// <param name="parser"></param>
        /// <param name="except"></param>
        /// <returns></returns>
        public static Parser <TToken, T> Except <TToken, T, U>(this Parser <TToken, T> parser, Parser <TToken, U> except)
        {
            if (parser == null)
            {
                throw new ArgumentNullException(nameof(parser));
            }
            if (except == null)
            {
                throw new ArgumentNullException(nameof(except));
            }

            // Could be more like: except.Then(s => s.Fail("..")).XOr(parser)
            return((i, n) =>
            {
                var r = except(i, n);
                if (r.IsSuccess)
                {
                    return ParserResult <TToken, T> .Failure(i, new[] { "other than the excepted input" }, "Excepted parser succeeded.");
                }
                return parser(i, n);
            });
        }
Пример #10
0
        public static Parser <char, char> Char(Func <char, bool> predicate, string expected)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            return((i, n) =>
            {
                if (i.AtEnd)
                {
                    return ParserResult <char, char> .Failure(i, new[] { expected }, "Unexpected end of input");
                }

                if (predicate(i.GetCurrent()))
                {
                    return ParserResult <char, char> .Success(i.Advance(), i.GetCurrent());
                }

                return ParserResult <char, char> .Failure(i, new[] { expected }, $"Unexpected '{i.GetCurrent()}'");
            });
        }
Пример #11
0
        internal static ParserResult <ScriptToken, T> TryParse <T>(this Parser <ScriptToken, T> parser, Network network, Script input)
        {
            if (parser == null)
            {
                throw new System.ArgumentNullException(nameof(parser));
            }

            if (input == null)
            {
                throw new System.ArgumentNullException(nameof(input));
            }

            try
            {
                return(parser(new ScriptInput(input), network));
            }
            // Catching exception here is bit ugly, but converting `Script` to `ScriptToken` is itself unsafe
            // so this is good for assuring purity of this method.
            catch (ParsingException e)
            {
                return(ParserResult <ScriptToken, T> .Failure(new ScriptInput(new ScriptToken[] { }), e.Message));
            }
        }