Пример #1
0
        /// <summary>
        /// Succeeds with a successful parser, if any.
        /// </summary>
        /// <remarks>The first successful parser that advances the text position is returned.
        /// Otherwise, the first successful parser that does not advance the text position is returned.
        /// Otherwise, the first failure is returned.</remarks>
        public static IParser <T> Or <T>(IEnumerable <IParser <T> > parsers)
        {
            return(Create(position =>
            {
                IParseResult <T> firstEmptySuccess = null;
                IParseResult <T> firstFailure = null;

                foreach (IParser <T> parser in parsers)
                {
                    IParseResult <T> result = parser.TryParse(position);
                    if (!result.Success)
                    {
                        firstFailure = firstFailure ?? result;
                    }
                    else if (result.NextPosition == position)
                    {
                        firstEmptySuccess = firstEmptySuccess ?? result;
                    }
                    else
                    {
                        return result;
                    }
                }

                return firstEmptySuccess ?? firstFailure ?? ParseResult.Failure <T>(position);
            }));
        }
Пример #2
0
        /// <summary>
        /// Parses the specified string using the specified string comparison.
        /// </summary>
        public static IParser <string> String(string text, StringComparison comparison)
        {
            return(Create(position =>
            {
                string inputText = position.Text;
                int inputIndex = position.Index;
                int textLength = text.Length;
                if (string.Compare(inputText, inputIndex, text, 0, textLength, comparison) == 0)
                {
                    return ParseResult.Success(inputText.Substring(inputIndex, textLength), position.WithNextIndex(textLength));
                }

                return ParseResult.Failure <string>(position);
            }));
        }
Пример #3
0
        /// <summary>
        /// Parses a single character if the specified predicate returns true.
        /// </summary>
        public static IParser <char> Char(Func <char, bool> test)
        {
            return(Create(position =>
            {
                if (!position.IsAtEnd())
                {
                    char current = position.GetCurrentChar();
                    if (test(current))
                    {
                        return ParseResult.Success(current, position.WithNextIndex());
                    }
                }

                return ParseResult.Failure <char>(position);
            }));
        }
Пример #4
0
        /// <summary>
        /// Succeeds if the specified regular expression pattern matches the text.
        /// </summary>
        /// <remarks>The regular expression pattern is automatically anchored at the beginning
        /// of the text, but not at the end of the text. The parsed value is the successful Match.</remarks>
        public static IParser <Match> Regex(string pattern, RegexOptions regexOptions = RegexOptions.None)
        {
            // turn off multiline mode for '^'; wrap pattern in non-capturing group to ensure ungrouped '|' works properly
            var regex = new Regex("(?-m:^)(?:" + pattern + ")", regexOptions);

            return(Create(position =>
            {
                int inputIndex = position.Index;
                string inputText = position.Text;
                var match = regex.Match(inputText, inputIndex, inputText.Length - inputIndex);
                if (match.Success)
                {
                    return ParseResult.Success(match, position.WithNextIndex(match.Length));
                }

                return ParseResult.Failure <Match>(position);
            }));
        }
Пример #5
0
 /// <summary>
 /// Succeeds only at the end of the text.
 /// </summary>
 public static IParser <T> End <T>(this IParser <T> parser)
 {
     return(Create(position => parser.TryParse(position)
                   .MapSuccess(result => result.NextPosition.IsAtEnd() ? result : ParseResult.Failure <T>(result.NextPosition))));
 }
Пример #6
0
 /// <summary>
 /// Fails if the specified predicate returns false for the successfully parsed value.
 /// </summary>
 public static IParser <T> Where <T>(this IParser <T> parser, Func <T, bool> predicate) =>
 Create(position => parser.TryParse(position).MapSuccess(result => predicate(result.Value) ? result : ParseResult.Failure <T>(position)));
Пример #7
0
        private static IParser <IReadOnlyList <T> > DoRepeat <T>(this IParser <T> parser, int atLeast, int?atMost)
        {
            return(Create(position =>
            {
                List <T> values = new List <T>(capacity: atLeast);
                TextPosition remainder = position;
                int repeated = 0;

                while (true)
                {
                    if (repeated >= atMost)
                    {
                        break;
                    }
                    IParseResult <T> result = parser.TryParse(remainder);
                    if (!result.Success || result.NextPosition == remainder)
                    {
                        break;
                    }
                    values.Add(result.Value);
                    remainder = result.NextPosition;
                    repeated++;
                }

                return repeated >= atLeast ? ParseResult.Success <IReadOnlyList <T> >(values, remainder) : ParseResult.Failure <IReadOnlyList <T> >(position);
            }));
        }