Optimize QML parser
authorMartin Jones <martin.jones@nokia.com>
Fri, 18 May 2012 04:24:59 +0000 (14:24 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 24 May 2012 00:35:03 +0000 (02:35 +0200)
Inlining and faster number parsing.  Reduces parsing of large
project from 20.5mil instr to 19mil instr.

Change-Id: I83aff3eaf03fd19b07f5e84ec6f9d17b7f0cb931
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
src/qml/qml/parser/qqmljslexer.cpp
src/qml/qml/parser/qqmljslexer_p.h

index c34fc81..a4c5f72 100644 (file)
@@ -671,6 +671,17 @@ again:
         _errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
         return T_ERROR;
     }
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+        return scanNumber(ch);
 
     default:
         if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
@@ -727,118 +738,127 @@ again:
                     return kind;
                 }
             }
-        } else if (ch.isDigit()) {
-            if (ch != QLatin1Char('0')) {
-                double integer = ch.unicode() - '0';
-
-                QChar n = _char;
-                const QChar *code = _codePtr;
-                while (n.isDigit()) {
-                    integer = integer * 10 + (n.unicode() - '0');
-                    n = *code++;
-                }
+        }
 
-                if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
-                    if (code != _codePtr) {
-                        _codePtr = code - 1;
-                        scanChar();
-                    }
-                    _tokenValue = integer;
-                    return T_NUMERIC_LITERAL;
-                }
-            }
+        break;
+    }
 
-            QVarLengthArray<char,32> chars;
-            chars.append(ch.unicode());
+    return T_ERROR;
+}
 
-            if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
-                // parse hex integer literal
+int Lexer::scanNumber(QChar ch)
+{
+    if (ch != QLatin1Char('0')) {
+        double integer = ch.unicode() - '0';
+
+        QChar n = _char;
+        const QChar *code = _codePtr;
+        while (n.isDigit()) {
+            integer = integer * 10 + (n.unicode() - '0');
+            n = *code++;
+        }
 
-                chars.append(_char.unicode());
-                scanChar(); // consume `x'
+        if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
+            if (code != _codePtr) {
+                _codePtr = code - 1;
+                scanChar();
+            }
+            _tokenValue = integer;
+            return T_NUMERIC_LITERAL;
+        }
+    }
 
-                while (isHexDigit(_char)) {
-                    chars.append(_char.unicode());
-                    scanChar();
-                }
+    QVarLengthArray<char,32> chars;
+    chars.append(ch.unicode());
 
-                _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
-                return T_NUMERIC_LITERAL;
-            }
+    if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
+        // parse hex integer literal
 
-            // decimal integer literal
-            while (_char.isDigit()) {
-                chars.append(_char.unicode());
-                scanChar(); // consume the digit
-            }
+        chars.append(_char.unicode());
+        scanChar(); // consume `x'
 
-            if (_char == QLatin1Char('.')) {
-                chars.append(_char.unicode());
-                scanChar(); // consume `.'
+        while (isHexDigit(_char)) {
+            chars.append(_char.unicode());
+            scanChar();
+        }
 
-                while (_char.isDigit()) {
-                    chars.append(_char.unicode());
-                    scanChar();
-                }
+        _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
+        return T_NUMERIC_LITERAL;
+    }
 
-                if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
-                    if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
-                                                  _codePtr[1].isDigit())) {
+    // decimal integer literal
+    while (_char.isDigit()) {
+        chars.append(_char.unicode());
+        scanChar(); // consume the digit
+    }
 
-                        chars.append(_char.unicode());
-                        scanChar(); // consume `e'
+    if (_char == QLatin1Char('.')) {
+        chars.append(_char.unicode());
+        scanChar(); // consume `.'
 
-                        if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
-                            chars.append(_char.unicode());
-                            scanChar(); // consume the sign
-                        }
+        while (_char.isDigit()) {
+            chars.append(_char.unicode());
+            scanChar();
+        }
 
-                        while (_char.isDigit()) {
-                            chars.append(_char.unicode());
-                            scanChar();
-                        }
-                    }
+        if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+            if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+                                          _codePtr[1].isDigit())) {
+
+                chars.append(_char.unicode());
+                scanChar(); // consume `e'
+
+                if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+                    chars.append(_char.unicode());
+                    scanChar(); // consume the sign
                 }
-            } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
-                if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
-                                              _codePtr[1].isDigit())) {
 
+                while (_char.isDigit()) {
                     chars.append(_char.unicode());
-                    scanChar(); // consume `e'
+                    scanChar();
+                }
+            }
+        }
+    } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+        if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+                                      _codePtr[1].isDigit())) {
 
-                    if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
-                        chars.append(_char.unicode());
-                        scanChar(); // consume the sign
-                    }
+            chars.append(_char.unicode());
+            scanChar(); // consume `e'
 
-                    while (_char.isDigit()) {
-                        chars.append(_char.unicode());
-                        scanChar();
-                    }
-                }
+            if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+                chars.append(_char.unicode());
+                scanChar(); // consume the sign
             }
 
-            chars.append('\0');
+            while (_char.isDigit()) {
+                chars.append(_char.unicode());
+                scanChar();
+            }
+        }
+    }
 
-            const char *begin = chars.constData();
-            const char *end = 0;
-            bool ok = false;
+    if (chars.length() == 1) {
+        // if we ended up with a single digit, then it was a '0'
+        _tokenValue = 0;
+        return T_NUMERIC_LITERAL;
+    }
 
-            _tokenValue = qstrtod(begin, &end, &ok);
+    chars.append('\0');
 
-            if (end - begin != chars.size() - 1) {
-                _errorCode = IllegalExponentIndicator;
-                _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
-                return T_ERROR;
-            }
+    const char *begin = chars.constData();
+    const char *end = 0;
+    bool ok = false;
 
-            return T_NUMERIC_LITERAL;
-        }
+    _tokenValue = qstrtod(begin, &end, &ok);
 
-        break;
+    if (end - begin != chars.size() - 1) {
+        _errorCode = IllegalExponentIndicator;
+        _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+        return T_ERROR;
     }
 
-    return T_ERROR;
+    return T_NUMERIC_LITERAL;
 }
 
 bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
@@ -970,31 +990,6 @@ bool Lexer::isOctalDigit(ushort c)
     return (c >= '0' && c <= '7');
 }
 
-int Lexer::tokenKind() const
-{
-    return _tokenKind;
-}
-
-int Lexer::tokenOffset() const
-{
-    return _tokenStartPtr - _code.unicode();
-}
-
-int Lexer::tokenLength() const
-{
-    return _tokenLength;
-}
-
-int Lexer::tokenStartLine() const
-{
-    return _tokenLine;
-}
-
-int Lexer::tokenStartColumn() const
-{
-    return _tokenStartPtr - _tokenLinePtr + 1;
-}
-
 int Lexer::tokenEndLine() const
 {
     return _currentLineNumber;
@@ -1005,16 +1000,6 @@ int Lexer::tokenEndColumn() const
     return _codePtr - _lastLinePtr;
 }
 
-QStringRef Lexer::tokenSpell() const
-{
-    return _tokenSpell;
-}
-
-double Lexer::tokenValue() const
-{
-    return _tokenValue;
-}
-
 QString Lexer::tokenText() const
 {
     if (_validTokenText)
index 6b51852..65adf0a 100644 (file)
@@ -158,18 +158,18 @@ public:
     int regExpFlags() const { return _patternFlags; }
     QString regExpPattern() const { return _tokenText; }
 
-    int tokenKind() const;
-    int tokenOffset() const;
-    int tokenLength() const;
+    int tokenKind() const { return _tokenKind; }
+    int tokenOffset() const { return _tokenStartPtr - _code.unicode(); }
+    int tokenLength() const { return _tokenLength; }
 
-    int tokenStartLine() const;
-    int tokenStartColumn() const;
+    int tokenStartLine() const { return _tokenLine; }
+    int tokenStartColumn() const { return _tokenStartPtr - _tokenLinePtr + 1; }
 
     int tokenEndLine() const;
     int tokenEndColumn() const;
 
-    QStringRef tokenSpell() const;
-    double tokenValue() const;
+    inline QStringRef tokenSpell() const { return _tokenSpell; }
+    double tokenValue() const { return _tokenValue; }
     QString tokenText() const;
 
     Error errorCode() const;
@@ -191,6 +191,7 @@ protected:
 private:
     inline void scanChar();
     int scanToken();
+    int scanNumber(QChar ch);
 
     bool isLineTerminator() const;
     static bool isIdentLetter(QChar c);