This class supports "Match and Forward" pattern. On a failed match, the SetError method sets the ErrorMessage. On a successful match, the StartIndex is updated by a call to Forward so that the Head is positioned after the match (and any existing error is cleared). There are 2 main kind of methods: TryMatchXXX that when the match fails returns false but do not call SetErrorand MatchXXX that do set an error on failure. This class does not actually hide/encapsulate a lot of things: it is designed to be extended through extension methods.
Exemplo n.º 1
0
        public void match_methods_must_set_an_error()
        {
            var m = new StringMatcher( "A" );

            DateTimeStamp ts;
            CheckMatchError( m, () => m.MatchDateTimeStamp( out ts ) );
            DateTime dt;
            CheckMatchError( m, () => m.MatchFileNameUniqueTimeUtcFormat( out dt ) );
            CheckMatchError( m, () => m.MatchText( "B" ) );
        }
Exemplo n.º 2
0
 private static void CheckMatchError( StringMatcher m, Func<bool> fail )
 {
     int idx = m.StartIndex;
     int len = m.Length;
     Assert.That( fail(), Is.False );
     Assert.That( m.IsError );
     Assert.That( m.ErrorMessage, Is.Not.Null.Or.Empty );
     Assert.That( m.StartIndex == idx, "Head must not move on error." );
     Assert.That( m.Length == len, "Length must not change on error." );
     m.SetSuccess();
 }
Exemplo n.º 3
0
        private static void CheckDateTimeStamp( DateTimeStamp t )
        {
            string s = t.ToString();
            var m = new StringMatcher( "X" + s + "Y" );
            Assert.That( m.MatchChar( 'X' ) );
            DateTimeStamp parsed;
            Assert.That( m.MatchDateTimeStamp( out parsed ) && parsed == t );
            Assert.That( m.MatchChar( 'Y' ) );

            m = new StringMatcher( s.Insert( 2, "X" ) );
            Assert.That( m.MatchDateTimeStamp( out parsed ), Is.False );
            Assert.That( m.ErrorMessage, Is.Not.Null );
            int i;
            Assert.That( m.MatchInt32( out i ) && i == 20 );
        }
Exemplo n.º 4
0
        public void matching_FileNameUniqueTimeUtcFormat()
        {
            DateTime t = DateTime.UtcNow;
            string s = t.ToString( FileUtil.FileNameUniqueTimeUtcFormat );
            var m = new StringMatcher( "X" + s + "Y" );
            Assert.That( m.MatchChar( 'X' ) );
            DateTime parsed;
            Assert.That( m.MatchFileNameUniqueTimeUtcFormat( out parsed ) && parsed == t );
            Assert.That( m.MatchChar( 'Y' ) );

            m = new StringMatcher( s.Insert( 2, "X" ) );
            Assert.That( m.MatchFileNameUniqueTimeUtcFormat( out parsed ), Is.False );
            int i;
            Assert.That( m.MatchInt32( out i ) && i == 20 );
        }
Exemplo n.º 5
0
 /// <summary>
 /// Matches a very simple version of a JSON object content: this match stops at the first closing }.
 /// Whitespaces and JS comments (//... or /* ... */) are skipped.
 /// </summary>
 /// <param name="this">This <see cref="StringMatcher"/>.</param>
 /// <param name="o">The read object on success as a list of KeyValuePair.</param>
 /// <returns>True on success, false on error.</returns>
 public static bool MatchJSONObjectContent(this StringMatcher @this, out List <KeyValuePair <string, object> > o)
 {
     o = null;
     while ([email protected])
     {
         @this.SkipWhiteSpacesAndJSComments();
         string propName;
         object value;
         if (@this.TryMatchChar('}'))
         {
             if (o == null)
             {
                 o = new List <KeyValuePair <string, object> >();
             }
             return(true);
         }
         if ([email protected](out propName))
         {
             o = null;
             return(@this.SetError("Quoted Property Name."));
         }
         @this.SkipWhiteSpacesAndJSComments();
         if ([email protected](':') || !MatchJSONObject(@this, out value))
         {
             o = null;
             return(false);
         }
         if (o == null)
         {
             o = new List <KeyValuePair <string, object> >();
         }
         o.Add(new KeyValuePair <string, object>(propName, value));
         @this.SkipWhiteSpacesAndJSComments();
         // This accepts e trailing comma at the end of a property list: ..."a":0,} is not an error.
         @this.TryMatchChar(',');
     }
     return(@this.SetError("JSON object definition but reached end of match."));
 }
 /// <summary>
 /// Tries to match a //.... or /* ... */ comment.
 /// Proper termination of comment (by a new line or the closing */) is not required:
 /// a ending /*... is considered valid.
 /// </summary>
 /// <param name="this">This <see cref="StringMatcher"/>.</param>
 /// <returns>True on success, false if the <see cref="StringMatcher.Head"/> is not on a /.</returns>
 public static bool TryMatchJSComment(this StringMatcher @this)
 {
     if ([email protected]('/'))
     {
         return(false);
     }
     if (@this.TryMatchChar('/'))
     {
         while ([email protected] && @this.Head != '\n')
         {
             @this.UncheckedMove(1);
         }
         if ([email protected])
         {
             @this.UncheckedMove(1);
         }
         return(true);
     }
     else if (@this.TryMatchChar('*'))
     {
         while ([email protected])
         {
             if (@this.Head == '*')
             {
                 @this.UncheckedMove(1);
                 if (@this.IsEnd || @this.TryMatchChar('/'))
                 {
                     return(true);
                 }
             }
             @this.UncheckedMove(1);
         }
         return(true);
     }
     @this.UncheckedMove(-1);
     return(false);
 }
        /// <summary>
        /// Matches a JSON quoted string without setting an error if match fails.
        /// </summary>
        /// <param name="this">This <see cref="StringMatcher"/>.</param>
        /// <param name="content">Extracted content.</param>
        /// <param name="allowNull">True to allow 'null'.</param>
        /// <returns><c>true</c> when matched, <c>false</c> otherwise.</returns>
        public static bool TryMatchJSONQuotedString(this StringMatcher @this, out string content, bool allowNull = false)
        {
            content = null;
            if (@this.IsEnd)
            {
                return(false);
            }
            int i = @this.StartIndex;

            if (@this.Text[i++] != '"')
            {
                return(allowNull && @this.TryMatchText("null"));
            }
            int           len = @this.Length - 1;
            StringBuilder b   = null;

            while (len >= 0)
            {
                if (len == 0)
                {
                    return(false);
                }
                char c = @this.Text[i++];
                --len;
                if (c == '"')
                {
                    break;
                }
                if (c == '\\')
                {
                    if (len == 0)
                    {
                        return(false);
                    }
                    if (b == null)
                    {
                        b = new StringBuilder(@this.Text, @this.StartIndex + 1, i - @this.StartIndex - 2, 1024);
                    }
                    switch ((c = @this.Text[i++]))
                    {
                    case 'r': c = '\r'; break;

                    case 'n': c = '\n'; break;

                    case 'b': c = '\b'; break;

                    case 't': c = '\t'; break;

                    case 'f': c = '\f'; break;

                    case 'u':
                    {
                        if (--len == 0)
                        {
                            return(false);
                        }
                        int cN;
                        cN = ReadHexDigit(@this.Text[i++]);
                        if (cN < 0 || cN > 15)
                        {
                            return(false);
                        }
                        int val = cN << 12;
                        if (--len == 0)
                        {
                            return(false);
                        }
                        cN = ReadHexDigit(@this.Text[i++]);
                        if (cN < 0 || cN > 15)
                        {
                            return(false);
                        }
                        val |= cN << 8;
                        if (--len == 0)
                        {
                            return(false);
                        }
                        cN = ReadHexDigit(@this.Text[i++]);
                        if (cN < 0 || cN > 15)
                        {
                            return(false);
                        }
                        val |= cN << 4;
                        if (--len == 0)
                        {
                            return(false);
                        }
                        cN = ReadHexDigit(@this.Text[i++]);
                        if (cN < 0 || cN > 15)
                        {
                            return(false);
                        }
                        val |= cN;
                        c    = (char)val;
                        break;
                    }
                    }
                }
                if (b != null)
                {
                    b.Append(c);
                }
            }
            int lenS = i - @this.StartIndex;

            if (b != null)
            {
                content = b.ToString();
            }
            else
            {
                content = @this.Text.Substring(@this.StartIndex + 1, lenS - 2);
            }
            return(@this.UncheckedMove(lenS));
        }
Exemplo n.º 8
0
 /// <summary>
 /// Initializes a new <see cref="JSONVisitor"/> bound to a <see cref="Matcher"/>.
 /// </summary>
 /// <param name="m">The string matcher.</param>
 public JSONVisitor(StringMatcher m)
 {
     _m    = m;
     _path = new List <Parent>();
 }
Exemplo n.º 9
0
 /// <summary>
 /// Initializes a new <see cref="JSONVisitor"/> bound to a <see cref="Matcher"/>.
 /// </summary>
 /// <param name="m">The string matcher.</param>
 public JSONVisitor( StringMatcher m )
 {
     _m = m;
     _path = new List<Parent>();
 }
Exemplo n.º 10
0
 public static bool TryMatchJSONValue(this StringMatcher @this, out object value) => TryMatchJSONTerminalValue(@this, out value);