/// <summary>
        /// Performs common parsing operations: start with a parse action to move the
        /// value cursor onto the first character, then call a character handler for each
        /// character in the pattern to build up the steps. If any handler fails,
        /// that failure is returned - otherwise the return value is null.
        /// </summary>
        internal void ParseCustomPattern(string patternText,
                                         Dictionary <char, CharacterHandler <TResult, TBucket> > characterHandlers)
        {
            var patternCursor = new PatternCursor(patternText);

            // Now iterate over the pattern.
            while (patternCursor.MoveNext())
            {
                CharacterHandler <TResult, TBucket> handler;
                if (characterHandlers.TryGetValue(patternCursor.Current, out handler))
                {
                    handler(patternCursor, this);
                }
                else
                {
                    char current = patternCursor.Current;
                    if ((current >= 'A' && current <= 'Z') || (current >= 'a' && current <= 'z') ||
                        current == PatternCursor.EmbeddedPatternStart || current == PatternCursor.EmbeddedPatternEnd)
                    {
                        throw new InvalidPatternException(TextErrorMessages.UnquotedLiteral, current);
                    }
                    AddLiteral(patternCursor.Current, ParseResult <TResult> .MismatchedCharacter);
                }
            }
        }
示例#2
0
 public void TestGetQuotedString_EscapeAtEnd()
 {
     var cursor = new PatternCursor("'abc\\");
     Assert.AreEqual('\'', GetNextCharacter(cursor));
     cursor.GetQuotedString('\'', ref failure);
     Assert.Throws<InvalidPatternException>(() => failure.GetResultOrThrow());
 }
示例#3
0
 public void GetRepeatCount_Valid(string text, int expectedCount)
 {
     var cursor = new PatternCursor(text);
     Assert.IsTrue(cursor.MoveNext());
     int actual = cursor.GetRepeatCount(10);
     Assert.AreEqual(expectedCount, actual);
     ValidateCurrentCharacter(cursor, expectedCount - 1, 'a');
 }
示例#4
0
 public void GetQuotedString_Valid(string pattern, string expected)
 {
     var cursor = new PatternCursor(pattern);
     Assert.AreEqual('\'', GetNextCharacter(cursor));
     string actual = cursor.GetQuotedString('\'');
     Assert.AreEqual(expected, actual);
     Assert.IsFalse(cursor.MoveNext());
 }
 public void TestGetQuotedString_HandlesEscapedCloseQuote()
 {
     var cursor = new PatternCursor("'ab\\'c'");
     char openQuote = GetNextCharacter(cursor);
     string actual = cursor.GetQuotedString(openQuote);
     Assert.AreEqual("ab'c", actual);
     Assert.IsFalse(cursor.MoveNext());
 }
 public void TestGetQuotedString_HandlesOtherQuote()
 {
     var cursor = new PatternCursor("[abc]");
     GetNextCharacter(cursor);
     string actual = cursor.GetQuotedString(']');
     Assert.AreEqual("abc", actual);
     Assert.IsFalse(cursor.MoveNext());
 }
 public void TestGetQuotedString_Empty()
 {
     var cursor = new PatternCursor("''");
     char openQuote = GetNextCharacter(cursor);
     string actual = cursor.GetQuotedString(openQuote);
     Assert.AreEqual(string.Empty, actual);
     Assert.IsFalse(cursor.MoveNext());
 }
示例#8
0
 internal static void HandleBackslash(PatternCursor pattern, SteppedPatternBuilder <TResult, TBucket> builder)
 {
     if (!pattern.MoveNext())
     {
         throw new InvalidPatternException(TextErrorMessages.EscapeAtEndOfString);
     }
     builder.AddLiteral(pattern.Current, ParseResult <TResult> .EscapedCharacterMismatch);
 }
 public void TestGetQuotedString()
 {
     var cursor = new PatternCursor("'abc'");
     Assert.AreEqual('\'', GetNextCharacter(cursor));
     string actual = cursor.GetQuotedString('\'');
     Assert.AreEqual("abc", actual);
     Assert.IsFalse(cursor.MoveNext());
 }
示例#10
0
 public void TestGetQuotedString_handlesDoubleQuote()
 {
     var cursor = new PatternCursor("\"abc\"");
     char openQuote = GetNextCharacter(cursor);
     string actual = cursor.GetQuotedString(openQuote, ref failure);
     Assert.AreEqual("abc", actual);
     Assert.IsFalse(cursor.MoveNext());
 }
示例#11
0
        public void GetQuotedString_NotAtEnd()
        {
            var cursor = new PatternCursor("'abc'more");
            char openQuote = GetNextCharacter(cursor);
            string actual = cursor.GetQuotedString(openQuote);
            Assert.AreEqual("abc", actual);
            ValidateCurrentCharacter(cursor, 4, '\'');

            Assert.AreEqual('m', GetNextCharacter(cursor));
        }
 /// <summary>
 /// Handle a leading "%" which acts as a pseudo-escape - it's mostly used to allow format strings such as "%H" to mean
 /// "use a custom format string consisting of H instead of a standard pattern H".
 /// </summary>
 internal static void HandlePercent(PatternCursor pattern, SteppedPatternBuilder <TResult, TBucket> builder)
 {
     if (pattern.HasMoreCharacters)
     {
         if (pattern.PeekNext() != '%')
         {
             // Handle the next character as normal
             return;
         }
         throw new InvalidPatternException(TextErrorMessages.PercentDoubled);
     }
     throw new InvalidPatternException(TextErrorMessages.PercentAtEndOfString);
 }
        /// <summary>
        /// Performs common parsing operations: start with a parse action to move the
        /// value cursor onto the first character, then call a character handler for each
        /// character in the pattern to build up the steps. If any handler fails,
        /// that failure is returned - otherwise the return value is null.
        /// </summary>
        internal void ParseCustomPattern(string patternText,
                                         Dictionary <char, CharacterHandler <TResult, TBucket> > characterHandlers)
        {
            var patternCursor = new PatternCursor(patternText);

            // Now iterate over the pattern.
            while (patternCursor.MoveNext())
            {
                CharacterHandler <TResult, TBucket> handler;
                if (characterHandlers.TryGetValue(patternCursor.Current, out handler))
                {
                    handler(patternCursor, this);
                }
                else
                {
                    AddLiteral(patternCursor.Current, ParseResult <TResult> .MismatchedCharacter);
                }
            }
        }
示例#14
0
 public void GetQuotedString_Invalid(string pattern)
 {
     var cursor = new PatternCursor(pattern);
     Assert.AreEqual('\'', GetNextCharacter(cursor));
     Assert.Throws<InvalidPatternException>(() => cursor.GetQuotedString('\''));
 }
示例#15
0
 public void GetEmbeddedPattern_Valid(string pattern, string expectedEmbedded)
 {
     var cursor = new PatternCursor(pattern);
     cursor.MoveNext();
     string embedded = cursor.GetEmbeddedPattern();
     Assert.AreEqual(expectedEmbedded, embedded);
     ValidateCurrentCharacter(cursor, expectedEmbedded.Length + 2, '>');
 }
示例#16
0
 public void TestGetRepeatCount_three()
 {
     var cursor = new PatternCursor("aaa");
     char ch = GetNextCharacter(cursor);
     int actual = cursor.GetRepeatCount(10, ch, ref failure);
     AssertNoFailure();
     Assert.AreEqual(3, actual);
     ValidateCurrentCharacter(cursor, 2, 'a');
 }
示例#17
0
 public void TestGetRepeatCount_exceedsMax()
 {
     var cursor = new PatternCursor("aaa");
     char ch = GetNextCharacter(cursor);
     cursor.GetRepeatCount(2, ch, ref failure);
     AssertInvalidPatternFailure();
 }
示例#18
0
 public void TestGetQuotedString_simple()
 {
     var cursor = new PatternCursor("'abc'");
     char openQuote = GetNextCharacter(cursor);
     string actual = cursor.GetQuotedString(openQuote, ref failure);
     AssertNoFailure();
     Assert.AreEqual("abc", actual);
     Assert.IsFalse(cursor.MoveNext());
 }
示例#19
0
 public void TestGetQuotedString_missingCloseQuote()
 {
     var cursor = new PatternCursor("'abc");
     char openQuote = GetNextCharacter(cursor);
     cursor.GetQuotedString(openQuote, ref failure);
     Assert.Throws<InvalidPatternException>(() => failure.GetResultOrThrow());
 }
示例#20
0
 public void TestGetRepeatCount_Three()
 {
     var cursor = new PatternCursor("aaa");
     Assert.IsTrue(cursor.MoveNext());
     int actual = cursor.GetRepeatCount(10);
     Assert.AreEqual(3, actual);
     ValidateCurrentCharacter(cursor, 2, 'a');
 }
示例#21
0
 public void TestGetEmbeddedPattern_Valid()
 {
     var cursor = new PatternCursor("x<HH:mm>y");
     cursor.MoveNext();
     string embedded = cursor.GetEmbeddedPattern('<', '>');
     Assert.AreEqual("HH:mm", embedded);
     ValidateCurrentCharacter(cursor, 7, '>');
 }
示例#22
0
 public void TestGetEmbeddedPattern_Valid_WithEscaping()
 {
     var cursor = new PatternCursor(@"x<HH:\Tmm>y");
     cursor.MoveNext();
     string embedded = cursor.GetEmbeddedPattern('<', '>');
     Assert.AreEqual(@"HH:\Tmm", embedded);
     Assert.AreEqual('>', cursor.Current);
 }
示例#23
0
 public void TestGetEmbeddedPattern_WrongOpenCharacter()
 {
     var cursor = new PatternCursor("x(oops)");
     cursor.MoveNext();
     Assert.Throws<InvalidPatternException>(() => cursor.GetEmbeddedPattern('<', '>'));
 }
示例#24
0
 public void TestGetEmbeddedPattern_QuotedCloseCharacter()
 {
     var cursor = new PatternCursor("x<oops'>'");
     cursor.MoveNext();
     Assert.Throws<InvalidPatternException>(() => cursor.GetEmbeddedPattern('<', '>'));
 }
示例#25
0
 public void TestGetQuotedString_MissingCloseQuote()
 {
     var cursor = new PatternCursor("'abc");
     char openQuote = GetNextCharacter(cursor);
     Assert.Throws<InvalidPatternException>(() => cursor.GetQuotedString(openQuote));
 }
示例#26
0
        /// <summary>
        /// Returns true if the next character in the pattern might represent a digit from another value (e.g. a different
        /// field). Returns false otherwise, e.g. if we've reached the end of the pattern, or the next character is a literal
        /// non-digit.
        /// </summary>
        private static bool CheckIfNextCharacterMightBeDigit(PatternCursor pattern)
        {
            int originalIndex = pattern.Index;

            try
            {
                if (!pattern.MoveNext())
                {
                    return(false);
                }
                char next = pattern.Current;
                // If we've got an unescaped letter, assume it could be a field.
                // If we've got an unescaped digit, it's a no-brainer.
                if ((next >= '0' && next <= '9') || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))
                {
                    return(true);
                }
                // A % is tricky - could be any number of things. Act conservatively.
                if (next == '%')
                {
                    return(true);
                }
                // Quoting: find the unquoted text, and see whether it starts with a non-digit.
                if (next == '\'' || next == '\"')
                {
                    // If this throws, catch it and let it get thrown later, in the right context.
                    try
                    {
                        string quoted = pattern.GetQuotedString(next);
                        // Empty quotes - could be trying to disguise a digit afterwards...
                        if (quoted.Length == 0)
                        {
                            return(true);
                        }
                        char firstQuoted = quoted[0];
                        // Check if the quoted string starts with a digit, basically.
                        return(firstQuoted >= '0' && firstQuoted <= '9');
                    }
                    catch (InvalidPatternException)
                    {
                        // Doesn't really matter...
                        return(true);
                    }
                }
                if (next == '\\')
                {
                    if (!pattern.MoveNext())
                    {
                        return(true); // Doesn't really matter; we'll throw an exception soon anyway.
                    }
                    char quoted = pattern.Current;
                    return(quoted >= '0' && quoted <= '9');
                }
                // Could be a date/time separator, but otherwise it's just something that we'll include
                // as a literal and won't be a digit.
                return(false);
            }
            finally
            {
                pattern.Move(originalIndex);
            }
        }
示例#27
0
        internal static void HandleQuote(PatternCursor pattern, SteppedPatternBuilder <TResult, TBucket> builder)
        {
            string quoted = pattern.GetQuotedString(pattern.Current);

            builder.AddLiteral(quoted, ParseResult <TResult> .QuotedStringMismatch);
        }
示例#28
0
 public void TestGetRepeatCount_ExceedsMax()
 {
     var cursor = new PatternCursor("aaa");
     Assert.IsTrue(cursor.MoveNext());
     Assert.Throws<InvalidPatternException>(() => cursor.GetRepeatCount(2));
 }
示例#29
0
        /// <summary>
        /// Handles date, time and date/time embedded patterns.
        /// </summary>
        internal void AddEmbeddedLocalPartial(
            PatternCursor pattern,
            Func <TBucket, LocalDatePatternParser.LocalDateParseBucket> dateBucketExtractor,
            Func <TBucket, LocalTimePatternParser.LocalTimeParseBucket> timeBucketExtractor,
            Func <TResult, LocalDate> dateExtractor,
            Func <TResult, LocalTime> timeExtractor,
            // null if date/time embedded patterns are invalid
            Func <TResult, LocalDateTime>?dateTimeExtractor)
        {
            // This will be d (date-only), t (time-only), or < (date and time)
            // If it's anything else, we'll see the problem when we try to get the pattern.
            var patternType = pattern.PeekNext();

            if (patternType == 'd' || patternType == 't')
            {
                pattern.MoveNext();
            }
            string embeddedPatternText = pattern.GetEmbeddedPattern();

            switch (patternType)
            {
            case '<':
            {
                var sampleBucket = CreateSampleBucket();
                var templateTime = timeBucketExtractor(sampleBucket).TemplateValue;
                var templateDate = dateBucketExtractor(sampleBucket).TemplateValue;
                if (dateTimeExtractor is null)
                {
                    throw new InvalidPatternException(TextErrorMessages.InvalidEmbeddedPatternType);
                }
                AddField(PatternFields.EmbeddedDate, 'l');
                AddField(PatternFields.EmbeddedTime, 'l');
                AddEmbeddedPattern(
                    LocalDateTimePattern.Create(embeddedPatternText, FormatInfo, templateDate + templateTime).UnderlyingPattern,
                    (bucket, value) =>
                    {
                        var dateBucket                = dateBucketExtractor(bucket);
                        var timeBucket                = timeBucketExtractor(bucket);
                        dateBucket.Calendar           = value.Calendar;
                        dateBucket.Year               = value.Year;
                        dateBucket.MonthOfYearNumeric = value.Month;
                        dateBucket.DayOfMonth         = value.Day;
                        timeBucket.Hours24            = value.Hour;
                        timeBucket.Minutes            = value.Minute;
                        timeBucket.Seconds            = value.Second;
                        timeBucket.FractionalSeconds  = value.NanosecondOfSecond;
                    },
                    dateTimeExtractor);
                break;
            }

            case 'd':
                AddEmbeddedDatePattern('l', embeddedPatternText, dateBucketExtractor, dateExtractor);
                break;

            case 't':
                AddEmbeddedTimePattern('l', embeddedPatternText, timeBucketExtractor, timeExtractor);
                break;

            default:
                throw new InvalidOperationException("Bug in Noda Time: embedded pattern type wasn't date, time, or date+time");
            }
        }
示例#30
0
 public void GetEmbeddedPattern_Invalid(string text)
 {
     var cursor = new PatternCursor(text);
     cursor.MoveNext();
     Assert.Throws<InvalidPatternException>(() => cursor.GetEmbeddedPattern());
 }