2008-12-08 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Dec 2008 07:24:05 +0000 (07:24 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Dec 2008 07:24:05 +0000 (07:24 +0000)
        Reviewed by Oliver Hunt.

        Implemented more of the relaxed and somewhat weird rules for deciding
        how to interpret a non-pattern-character.

        * wrec/Escapes.h:
        (JSC::WREC::Escape::):
        (JSC::WREC::Escape::Escape): Eliminated Escape::None because it was
        unused. If you see an '\\', it's either a valid escape or an error.

        * wrec/Quantifier.h:
        (JSC::WREC::Quantifier::Quantifier):
        * wrec/WRECGenerator.cpp:
        (JSC::WREC::Generator::generateNonGreedyQuantifier):
        (JSC::WREC::Generator::generateGreedyQuantifier): Renamed "noMaxSpecified"
        to "Infinity", since that's what it means.

        * wrec/WRECParser.cpp:
        (JSC::WREC::Parser::consumeGreedyQuantifier): Re-wrote {n,m} parsing rules
        because they were too strict before. Added support for backtracking
        in the case where the {n,m} fails to parse as a quantifier, and yet is
        not a syntax error.

        (JSC::WREC::Parser::parseCharacterClass):
        (JSC::WREC::Parser::parseNonCharacterEscape): Eliminated Escape::None,
        as above.

        (JSC::WREC::Parser::consumeEscape): Don't treat ASCII and _ escapes
        as syntax errors. See fast/regex/non-pattern-characters.html.

        * wrec/WRECParser.h:
        (JSC::WREC::Parser::SavedState::SavedState):
        (JSC::WREC::Parser::SavedState::restore): Added a state backtracker,
        since parsing {n,m} forms requires backtracking if the form turns out
        not to be a quantifier.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@39130 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/wrec/Escapes.h
JavaScriptCore/wrec/Quantifier.h
JavaScriptCore/wrec/WRECGenerator.cpp
JavaScriptCore/wrec/WRECParser.cpp
JavaScriptCore/wrec/WRECParser.h

index 9c70e4d..c684a97 100644 (file)
@@ -2,6 +2,44 @@
 
         Reviewed by Oliver Hunt.
         
+        Implemented more of the relaxed and somewhat weird rules for deciding
+        how to interpret a non-pattern-character.
+        
+        * wrec/Escapes.h:
+        (JSC::WREC::Escape::):
+        (JSC::WREC::Escape::Escape): Eliminated Escape::None because it was
+        unused. If you see an '\\', it's either a valid escape or an error.
+
+        * wrec/Quantifier.h:
+        (JSC::WREC::Quantifier::Quantifier):
+        * wrec/WRECGenerator.cpp:
+        (JSC::WREC::Generator::generateNonGreedyQuantifier):
+        (JSC::WREC::Generator::generateGreedyQuantifier): Renamed "noMaxSpecified"
+        to "Infinity", since that's what it means.
+
+        * wrec/WRECParser.cpp:
+        (JSC::WREC::Parser::consumeGreedyQuantifier): Re-wrote {n,m} parsing rules
+        because they were too strict before. Added support for backtracking
+        in the case where the {n,m} fails to parse as a quantifier, and yet is
+        not a syntax error.
+
+        (JSC::WREC::Parser::parseCharacterClass):
+        (JSC::WREC::Parser::parseNonCharacterEscape): Eliminated Escape::None,
+        as above.
+
+        (JSC::WREC::Parser::consumeEscape): Don't treat ASCII and _ escapes
+        as syntax errors. See fast/regex/non-pattern-characters.html.
+        
+        * wrec/WRECParser.h:
+        (JSC::WREC::Parser::SavedState::SavedState):
+        (JSC::WREC::Parser::SavedState::restore): Added a state backtracker,
+        since parsing {n,m} forms requires backtracking if the form turns out
+        not to be a quantifier.
+
+2008-12-08  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Oliver Hunt.
+        
         Refactored WREC parsing so that only one piece of code needs to know
         the relaxed and somewhat weird rules for deciding how to interpret a
         non-pattern-character, in preparation for implementing those rules.
index 70ea825..16c1d6f 100644 (file)
@@ -39,7 +39,6 @@ namespace JSC { namespace WREC {
     class Escape {
     public:
         enum Type {
-            None,
             PatternCharacter,
             CharacterClass,
             Backreference,
@@ -47,7 +46,7 @@ namespace JSC { namespace WREC {
             Error,
         };
         
-        Escape(Type type = None)
+        Escape(Type type)
             : m_type(type)
         {
         }
index 5196679..3da74cd 100644 (file)
@@ -43,7 +43,7 @@ namespace JSC { namespace WREC {
             Error,
         };
 
-        Quantifier(Type type = None, unsigned min = 0, unsigned max = noMaxSpecified)
+        Quantifier(Type type = None, unsigned min = 0, unsigned max = Infinity)
             : type(type)
             , min(min)
             , max(max)
@@ -56,7 +56,7 @@ namespace JSC { namespace WREC {
         unsigned min;
         unsigned max;
 
-        static const unsigned noMaxSpecified = UINT_MAX;
+        static const unsigned Infinity = UINT_MAX;
     };
 
 } } // namespace JSC::WREC
index f77a0a5..704de80 100644 (file)
@@ -180,7 +180,7 @@ void Generator::generateNonGreedyQuantifier(JumpList& failures, GenerateAtomFunc
     // (3.1) remove the value pushed prior to testing the alternative
     pop(index);
     // (3.2) if there is a limit, and we have reached it, game over. 
-    if (max != Quantifier::noMaxSpecified) {
+    if (max != Quantifier::Infinity) {
         je32(repeatCount, Imm32(max), quantifierFailed);
     }
 
@@ -230,7 +230,7 @@ void Generator::generateGreedyQuantifier(JumpList& failures, GenerateAtomFunctor
     Label readAnAtom(this);
     functor.generateAtom(this, doneReadingAtoms);
     add32(Imm32(1), repeatCount);
-    if (max == Quantifier::noMaxSpecified)
+    if (max == Quantifier::Infinity)
         jump(readAnAtom);
     else if (max == 1)
         doneReadingAtoms.append(jump());
index 4ae9469..bca6ca9 100644 (file)
@@ -112,69 +112,42 @@ ALWAYS_INLINE Quantifier Parser::consumeGreedyQuantifier()
             return Quantifier(Quantifier::Greedy, 1);
 
         case '{': {
+            SavedState state(*this);
             consume();
-            // a numeric quantifier should always have a lower bound
+
+            // Accept: {n}, {n,}, {n,m}.
+            // Reject: {n,m} where n > m.
+            // Ignore: Anything else, such as {n, m}.
+
             if (!peekIsDigit()) {
-                m_error = MalformedQuantifier;
-                return Quantifier(Quantifier::Error);
+                state.restore();
+                return Quantifier();
             }
-            int min = consumeNumber();
-            
-            // this should either be a , or a }
-            switch (peek()) {
-            case '}':
-                // {n} - exactly n times. (technically I think a '?' is valid in the bnf - bit meaningless).
-                consume();
-                return Quantifier(Quantifier::Greedy, min, min);
 
-            case ',':
-                consume();
-                switch (peek()) {
-                case '}':
-                    // {n,} - n to inf times.
-                    consume();
-                    return Quantifier(Quantifier::Greedy, min);
-
-                case '0':
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                case '8':
-                case '9': {
-                    // {n,m} - n to m times.
-                    int max = consumeNumber();
-                    
-                    if (peek() != '}') {
-                        m_error = MalformedQuantifier;
-                        return Quantifier(Quantifier::Error);
-                    }
-                    consume();
-                    
-                    if (min > max) {
-                        m_error = MalformedQuantifier;
-                        return Quantifier(Quantifier::Error);
-                    }
-
-                    return Quantifier(Quantifier::Greedy, min, max);
-                }
+            unsigned min = consumeNumber();
+            unsigned max = min;
 
-                default:
-                    m_error = MalformedQuantifier;
-                    return Quantifier(Quantifier::Error);
-                }
+            if (peek() == ',') {
+                consume();
+                max = peekIsDigit() ? consumeNumber() : Quantifier::Infinity;
+            }
 
-            default:
+            if (peek() != '}') {
+                state.restore();
+                return Quantifier();
+            }
+            consume();
+            if (min > max) {
                 m_error = MalformedQuantifier;
                 return Quantifier(Quantifier::Error);
             }
-        }
-        // None of the above - no quantifier
-        default:
-            return Quantifier();
+
+            return Quantifier(Quantifier::Greedy, min, max);
+         }
+
+         default:
+            return Quantifier(); // No quantifier.
     }
 }
 
@@ -329,7 +302,6 @@ bool Parser::parseCharacterClass(JumpList& failures)
                     m_error = MalformedEscape;
                     return false;
                 }
-                case Escape::None:
                 case Escape::Backreference:
                 case Escape::WordBoundaryAssertion: {
                     ASSERT_NOT_REACHED();
@@ -377,9 +349,6 @@ bool Parser::parseNonCharacterEscape(JumpList& failures, const Escape& escape)
         case Escape::Error:
             m_error = MalformedEscape;
             return false;
-
-        case Escape::None:
-            return false;
     }
 
     ASSERT_NOT_REACHED();
@@ -508,13 +477,8 @@ Escape Parser::consumeEscape(bool inCharacterClass)
     }
 
     // IdentityEscape
-    default: {
-        // TODO: check this test for IdentifierPart.
-        int ch = consume();
-        if (isASCIIAlphanumeric(ch) || (ch == '_'))
-            return Escape(Escape::Error);
-        return PatternCharacterEscape(ch);
-    }
+    default:
+        return PatternCharacterEscape(consume());
     }
 }
 
index ba32f3a..9405f77 100644 (file)
@@ -44,6 +44,8 @@ namespace JSC { namespace WREC {
     typedef Generator::JumpList JumpList;
     typedef Generator::ParenthesesType ParenthesesType;
 
+    friend class SavedState;
+
     public:
         enum Error {
             NoError,
@@ -95,6 +97,24 @@ namespace JSC { namespace WREC {
         bool parseBackreferenceQuantifier(JumpList& failures, unsigned subpatternId);
 
     private:
+        class SavedState {
+        public:
+            SavedState(Parser& parser)
+                : m_parser(parser)
+                , m_index(parser.m_index)
+            {
+            }
+            
+            void restore()
+            {
+                m_parser.m_index = m_index;
+            }
+
+        private:
+            Parser& m_parser;
+            unsigned m_index;
+        };
+
         void reset()
         {
             m_index = 0;