Exemplo n.º 1
0
        /// <summary>
        /// TryParse a single character matching 'predicate'
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="description"></param>
        /// <returns></returns>
        public static Parser <char> Char(Predicate <char> predicate, string description)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("predicate");
            }
            if (description == null)
            {
                throw new ArgumentNullException("description");
            }

            return(i =>
            {
                if (!i.AtEnd)
                {
                    if (predicate(i.Current))
                    {
                        return Result.Success(i.Current, i.Advance());
                    }

                    return Result.Failure <char>(i,
                                                 Observe.Error(string.Format("unexpected '{0}'", i.Current), description));
                }

                return Result.Failure <char>(i,
                                             Observe.Error("Unexpected end of input reached", description));
            });
        }
Exemplo n.º 2
0
        /// <summary>
        /// Refer to another parser indirectly. This allows circular compile-time dependency between parsers.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reference"></param>
        /// <returns></returns>
        public static Parser <T> Ref <T>(Func <Parser <T> > reference)
        {
            if (reference == null)
            {
                throw new ArgumentNullException("reference");
            }

            Parser <T> p = null;

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

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

                i.Memos[p] = Result.Failure <T>(i,
                                                Observe.Error("Left recursion in the grammar."));

                var result = p(i);
                i.Memos[p] = result;
                return result;
            });
        }
Exemplo n.º 3
0
        /// <summary>
        /// Parse a stream of elements, attemting to skip over invalid elements.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parser"></param>
        /// <returns></returns>
        /// <remarks>Implemented imperatively to decrease stack usage.</remarks>
        public static Parser <IEnumerable <T> > ManyWithPanic <T, U>(this Parser <T> parser, Parser <U> panicUntil, string elementDescription)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }
            if (panicUntil == null)
            {
                throw new ArgumentNullException("panicUntil");
            }

            return(i =>
            {
                var remainder = i;
                var result = new List <T>();
                var observations = new List <ResultObservation>();

                var r = parser(i);

                while (true)
                {
                    if (r.WasSuccessful && remainder == r.Remainder)
                    {
                        break;
                    }

                    if (!r.WasSuccessful)
                    {
                        if (remainder == r.Remainder)
                        {
                            break;
                        }

                        observations.Add(Observe.Error("Unexpected {0}.", elementDescription));

                        remainder = r.Remainder;

                        var panicResult = panicUntil(remainder);

                        while (!panicResult.WasSuccessful && !remainder.AtEnd)
                        {
                            remainder = remainder.Advance();
                            panicResult = panicUntil(remainder);
                        }

                        remainder = panicResult.Remainder;
                    }
                    else
                    {
                        result.Add(r.Value);
                        remainder = r.Remainder;
                    }

                    r = parser(remainder);
                }

                return Result.Success <IEnumerable <T> >(result, remainder, observations);
            });
        }
Exemplo n.º 4
0
        /// <summary>
        /// Parse end-of-input.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parser"></param>
        /// <returns></returns>
        public static Parser <T> End <T>(this Parser <T> parser)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }

            return(i => parser(i).IfSuccess(s =>
                                            s.Remainder.AtEnd
                    ? s
                    : Result.Failure <T>(s.Remainder,
                                         Observe.Error(string.Format("unexpected '{0}'", s.Remainder.Current),
                                                       "end of input"))));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Constructs a parser that will fail if the given parser succeeds,
        /// and will succeed if the given parser fails. In any case, it won't
        /// consume any input. It's like a negative look-ahead in regex.
        /// </summary>
        /// <typeparam name="T">The result type of the given parser</typeparam>
        /// <param name="parser">The parser to wrap</param>
        /// <returns>A parser that is the opposite of the given parser.</returns>
        public static Parser <object> Not <T>(this Parser <T> parser)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }

            return(i =>
            {
                var result = parser(i);

                if (result.WasSuccessful)
                {
                    var msg = string.Format("'{0}' was not expected", string.Join(", ", result.Observations.SelectMany(x => x.Expectations)));
                    return Result.Failure <object>(i, Observe.Error(msg));
                }
                return Result.Success <object>(null, i);
            });
        }
Exemplo n.º 6
0
        /// <summary>
        /// Construct a parser from the given regular expression.
        /// </summary>
        /// <param name="regex">The regex expression.</param>
        /// <param name="description">Description of characters that don't match.</param>
        /// <returns>a parse of string</returns>
        public static Parser <string> Regex(Regex regex, string description = null)
        {
            if (regex == null)
            {
                throw new ArgumentNullException("regex");
            }

            var expectations = description == null
                ? new string[0]
                : new[] { description };

            return(i =>
            {
                if (!i.AtEnd)
                {
                    var remainder = i;
                    var input = i.Source.Substring(i.Position);
                    var match = regex.Match(input);

                    if (match.Success && match.Index == 0)
                    {
                        for (int j = 0; j < match.Length; j++)
                        {
                            remainder = remainder.Advance();
                        }

                        return Result.Success(match.Value, remainder);
                    }

                    var found = match.Index == input.Length
                                    ? "end of source"
                                    : string.Format("`{0}'", input[match.Index]);
                    return Result.Failure <string>(
                        remainder,
                        Observe.Error("string matching regex `" + regex.ToString() + "' expected but " + found + " found", expectations));
                }

                return Result.Failure <string>(i,
                                               Observe.Error("Unexpected end of input", expectations));
            });
        }
Exemplo n.º 7
0
        public static Parser <IEnumerable <T> > Repeat <T>(this Parser <T> parser, int count)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }

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

                for (var n = 0; n < count; ++n)
                {
                    var r = parser(remainder);
                    if (!r.WasSuccessful)
                    {
                        var what = r.Remainder.AtEnd
                            ? "end of input"
                            : r.Remainder.Current.ToString();

                        var msg = string.Format("Unexpected '{0}'", what);
                        var exp = string.Format("'{0}' {1} times, but was {2}", string.Join(", ", r.Observations.SelectMany(x => x.Expectations)), count, n);
                        return Result.Failure <IEnumerable <T> >(i,
                                                                 Observe.Error(msg, exp));
                    }

                    if (remainder != r.Remainder)
                    {
                        result.Add(r.Value);
                    }

                    remainder = r.Remainder;
                }

                return Result.Success <IEnumerable <T> >(result, remainder);
            });
        }
Exemplo n.º 8
0
        /// <summary>
        /// Attempt parsing only if the <paramref name="except"/> parser fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="U"></typeparam>
        /// <param name="parser"></param>
        /// <param name="except"></param>
        /// <returns></returns>
        public static Parser <T> Except <T, U>(this Parser <T> parser, Parser <U> except)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }
            if (except == null)
            {
                throw new ArgumentNullException("except");
            }

            // Could be more like: except.Then(s => s.Fail("..")).XOr(parser)
            return(i =>
            {
                var r = except(i);
                if (r.WasSuccessful)
                {
                    return Result.Failure <T>(i,
                                              Observe.Error("Excepted parser succeeded.", "other than the excepted input"));
                }
                return parser(i);
            });
        }
Exemplo n.º 9
0
        /// <summary>
        /// Succeed if the parsed value matches predicate.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parser"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static Parser <T> Where <T>(this Parser <T> parser, Func <T, bool> predicate)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }
            if (predicate == null)
            {
                throw new ArgumentNullException("predicate");
            }

            return(i => parser(i).IfSuccess(s =>
                                            predicate(s.Value) ? s : Result.Failure <T>(i,
                                                                                        Observe.Error(string.Format("Unexpected {0}.", s.Value)))));
        }
Exemplo n.º 10
0
        /// <summary>
        /// Names part of the grammar for help with error messages.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parser"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static Parser <T> Named <T>(this Parser <T> parser, string name)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            return(i => parser(i).IfFailure(f => f.Remainder == i ?
                                            Result.Failure <T>(f.Remainder, f.Observations.Concat(new[] { Observe.Error(string.Format("Rule named '{0}' failed.", name)) })) :
                                            f));
        }