Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / parser / qdeclarativejslexer.cpp
index 570548c..e292490 100644 (file)
@@ -1,8 +1,7 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the QtDeclarative module of the Qt Toolkit.
 **
 **
 **
 **
+**
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
 
 #include "qdeclarativejslexer_p.h"
 #include "qdeclarativejsengine_p.h"
-#include "qdeclarativejsnodepool_p.h"
-#include <private/qdeclarativeutils_p.h>
+#include "qdeclarativejsmemorypool_p.h"
+
 #include <QtCore/QCoreApplication>
 #include <QtCore/QVarLengthArray>
 #include <QtCore/QDebug>
@@ -53,18 +53,12 @@ QT_END_NAMESPACE
 
 using namespace QDeclarativeJS;
 
-enum RegExpFlag {
-    Global     = 0x01,
-    IgnoreCase = 0x02,
-    Multiline  = 0x04
-};
-
-static int flagFromChar(const QChar &ch)
+static int regExpFlagFromChar(const QChar &ch)
 {
     switch (ch.unicode()) {
-    case 'g': return Global;
-    case 'i': return IgnoreCase;
-    case 'm': return Multiline;
+    case 'g': return Lexer::RegExp_Global;
+    case 'i': return Lexer::RegExp_IgnoreCase;
+    case 'm': return Lexer::RegExp_Multiline;
     }
     return 0;
 }
@@ -79,9 +73,9 @@ static unsigned char convertHex(ushort c)
         return (c - 'A' + 10);
 }
 
-static unsigned char convertHex(QChar c1, QChar c2)
+static QChar convertHex(QChar c1, QChar c2)
 {
-    return ((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
+    return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
 }
 
 static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
@@ -104,28 +98,37 @@ Lexer::Lexer(Engine *engine)
     , _parenthesesCount(0)
     , _stackToken(-1)
     , _patternFlags(0)
+    , _tokenKind(0)
     , _tokenLength(0)
     , _tokenLine(0)
     , _validTokenText(false)
     , _prohibitAutomaticSemicolon(false)
     , _restrictedKeyword(false)
     , _terminator(false)
-    , _delimited(false)
+    , _followsClosingBrace(false)
+    , _delimited(true)
+    , _qmlMode(true)
 {
     if (engine)
         engine->setLexer(this);
 }
 
+bool Lexer::qmlMode() const
+{
+    return _qmlMode;
+}
+
 QString Lexer::code() const
 {
     return _code;
 }
 
-void Lexer::setCode(const QString &code, int lineno)
+void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
 {
     if (_engine)
         _engine->setCode(code);
 
+    _qmlMode = qmlMode;
     _code = code;
     _tokenText.clear();
     _tokenText.reserve(1024);
@@ -157,7 +160,8 @@ void Lexer::setCode(const QString &code, int lineno)
     _prohibitAutomaticSemicolon = false;
     _restrictedKeyword = false;
     _terminator = false;
-    _delimited = false;
+    _followsClosingBrace = false;
+    _delimited = true;
 }
 
 void Lexer::scanChar()
@@ -172,17 +176,21 @@ void Lexer::scanChar()
 
 int Lexer::lex()
 {
+    const int previousTokenKind = _tokenKind;
+
     _tokenSpell = QStringRef();
-    int token = scanToken();
+    _tokenKind = scanToken();
     _tokenLength = _codePtr - _tokenStartPtr - 1;
 
     _delimited = false;
     _restrictedKeyword = false;
+    _followsClosingBrace = (previousTokenKind == T_RBRACE);
 
     // update the flags
-    switch (token) {
+    switch (_tokenKind) {
     case T_LBRACE:
     case T_SEMICOLON:
+    case T_COLON:
         _delimited = true;
         break;
 
@@ -212,11 +220,11 @@ int Lexer::lex()
         break;
 
     case CountParentheses:
-        if (token == T_RPAREN) {
+        if (_tokenKind == T_RPAREN) {
             --_parenthesesCount;
             if (_parenthesesCount == 0)
                 _parenthesesState = BalancedParentheses;
-        } else if (token == T_LPAREN) {
+        } else if (_tokenKind == T_LPAREN) {
             ++_parenthesesCount;
         }
         break;
@@ -226,7 +234,7 @@ int Lexer::lex()
         break;
     } // switch
 
-    return token;
+    return _tokenKind;
 }
 
 bool Lexer::isUnicodeEscapeSequence(const QChar *chars)
@@ -278,7 +286,7 @@ again:
     _validTokenText = false;
     _tokenLinePtr = _lastLinePtr;
 
-    while (QDeclarativeUtils::isSpace(_char)) {
+    while (_char.isSpace()) {
         if (_char == QLatin1Char('\n')) {
             _tokenLinePtr = _codePtr;
 
@@ -389,6 +397,12 @@ again:
                     scanChar();
                     if (_char == QLatin1Char('/')) {
                         scanChar();
+
+                        if (_engine) {
+                            _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
+                                                tokenStartLine(), tokenStartColumn() + 2);
+                        }
+
                         goto again;
                     }
                 } else {
@@ -399,6 +413,10 @@ again:
             while (!_char.isNull() && _char != QLatin1Char('\n')) {
                 scanChar();
             }
+            if (_engine) {
+                _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+                                    tokenStartLine(), tokenStartColumn() + 2);
+            }
             goto again;
         } if (_char == QLatin1Char('=')) {
             scanChar();
@@ -407,19 +425,19 @@ again:
         return T_DIVIDE_;
 
     case '.':
-        if (QDeclarativeUtils::isDigit(_char)) {
+        if (_char.isDigit()) {
             QVarLengthArray<char,32> chars;
 
             chars.append(ch.unicode()); // append the `.'
 
-            while (QDeclarativeUtils::isDigit(_char)) {
+            while (_char.isDigit()) {
                 chars.append(_char.unicode());
                 scanChar();
             }
 
             if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
-                if (QDeclarativeUtils::isDigit(_codePtr[0]) || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
-                                              QDeclarativeUtils::isDigit(_codePtr[1]))) {
+                if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+                                              _codePtr[1].isDigit())) {
 
                     chars.append(_char.unicode());
                     scanChar(); // consume `e'
@@ -429,7 +447,7 @@ again:
                         scanChar(); // consume the sign
                     }
 
-                    while (QDeclarativeUtils::isDigit(_char)) {
+                    while (_char.isDigit()) {
                         chars.append(_char.unicode());
                         scanChar();
                     }
@@ -462,7 +480,7 @@ again:
             scanChar();
 
             if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
-                _stackToken = T_PLUS_PLUS;
+                _stackToken = T_MINUS_MINUS;
                 return T_SEMICOLON;
             }
 
@@ -529,11 +547,30 @@ again:
     case '\'':
     case '"': {
         const QChar quote = ch;
-        _tokenText.resize(0);
-        _validTokenText = true;
-
         bool multilineStringLiteral = false;
 
+        const QChar *startCode = _codePtr;
+
+        if (_engine) {
+            while (!_char.isNull()) {
+                if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) {
+                    break;
+                } else if (_char == quote) {
+                    _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
+                    scanChar();
+
+                    return T_STRING_LITERAL;
+                }
+                scanChar();
+            }
+        }
+
+        _validTokenText = true;
+        _tokenText.resize(0);
+        startCode--;
+        while (startCode != _codePtr - 1) 
+            _tokenText += *startCode++;
+
         while (! _char.isNull()) {
             if (_char == QLatin1Char('\n')) {
                 multilineStringLiteral = true;
@@ -579,7 +616,7 @@ again:
                     break;
 
                 // single character escape sequence
-                case '\\': u = QLatin1Char('\''); scanChar(); break;
+                case '\\': u = QLatin1Char('\\'); scanChar(); break;
                 case '\'': u = QLatin1Char('\''); scanChar(); break;
                 case '\"': u = QLatin1Char('\"'); scanChar(); break;
                 case 'b':  u = QLatin1Char('\b'); scanChar(); break;
@@ -603,7 +640,7 @@ again:
                     while (_char == QLatin1Char('\r'))
                         scanChar();
 
-                    if (_char == '\n') {
+                    if (_char == QLatin1Char('\n')) {
                         u = _char;
                         scanChar();
                     } else {
@@ -636,7 +673,7 @@ again:
     }
 
     default:
-        if (QDeclarativeUtils::isLetter(ch) || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
+        if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
             bool identifierWithEscapeChars = false;
             if (ch == QLatin1Char('\\')) {
                 identifierWithEscapeChars = true;
@@ -651,7 +688,7 @@ again:
                 }
             }
             while (true) {
-                if (QDeclarativeUtils::isLetterOrNumber(_char) || _char == QLatin1Char('$') || _char == QLatin1Char('_')) {
+                if (_char.isLetterOrNumber() || _char == QLatin1Char('$') || _char == QLatin1Char('_')) {
                     if (identifierWithEscapeChars)
                         _tokenText += _char;
 
@@ -678,7 +715,7 @@ again:
                     int kind = T_IDENTIFIER;
 
                     if (! identifierWithEscapeChars)
-                        kind = classify(_tokenStartPtr, _tokenLength);
+                        kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
 
                     if (_engine) {
                         if (kind == T_IDENTIFIER && identifierWithEscapeChars)
@@ -690,11 +727,31 @@ again:
                     return kind;
                 }
             }
-        } else if (QDeclarativeUtils::isDigit(ch)) {
+        } 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;
+                }
+            }
+
             QVarLengthArray<char,32> chars;
             chars.append(ch.unicode());
 
-            if (ch == QLatin1Char('0') && (_char == 'x' || _char == 'X')) {
+            if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
                 // parse hex integer literal
 
                 chars.append(_char.unicode());
@@ -710,7 +767,7 @@ again:
             }
 
             // decimal integer literal
-            while (QDeclarativeUtils::isDigit(_char)) {
+            while (_char.isDigit()) {
                 chars.append(_char.unicode());
                 scanChar(); // consume the digit
             }
@@ -719,14 +776,14 @@ again:
                 chars.append(_char.unicode());
                 scanChar(); // consume `.'
 
-                while (QDeclarativeUtils::isDigit(_char)) {
+                while (_char.isDigit()) {
                     chars.append(_char.unicode());
                     scanChar();
                 }
 
                 if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
-                    if (QDeclarativeUtils::isDigit(_codePtr[0]) || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
-                                                  QDeclarativeUtils::isDigit(_codePtr[1]))) {
+                    if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+                                                  _codePtr[1].isDigit())) {
 
                         chars.append(_char.unicode());
                         scanChar(); // consume `e'
@@ -736,15 +793,15 @@ again:
                             scanChar(); // consume the sign
                         }
 
-                        while (QDeclarativeUtils::isDigit(_char)) {
+                        while (_char.isDigit()) {
                             chars.append(_char.unicode());
                             scanChar();
                         }
                     }
                 }
             } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
-                if (QDeclarativeUtils::isDigit(_codePtr[0]) || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
-                                              QDeclarativeUtils::isDigit(_codePtr[1]))) {
+                if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+                                              _codePtr[1].isDigit())) {
 
                     chars.append(_char.unicode());
                     scanChar(); // consume `e'
@@ -754,7 +811,7 @@ again:
                         scanChar(); // consume the sign
                     }
 
-                    while (QDeclarativeUtils::isDigit(_char)) {
+                    while (_char.isDigit()) {
                         chars.append(_char.unicode());
                         scanChar();
                     }
@@ -806,7 +863,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
             // scan the flags
             _patternFlags = 0;
             while (isIdentLetter(_char)) {
-                int flag = flagFromChar(_char);
+                int flag = regExpFlagFromChar(_char);
                 if (flag == 0) {
                     _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Invalid regular expression flag '%0'")
                              .arg(QChar(_char));
@@ -815,6 +872,8 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
                 _patternFlags |= flag;
                 scanChar();
             }
+
+            _tokenLength = _codePtr - _tokenStartPtr - 1;
             return true;
 
         case '\\':
@@ -911,6 +970,11 @@ bool Lexer::isOctalDigit(ushort c)
     return (c >= '0' && c <= '7');
 }
 
+int Lexer::tokenKind() const
+{
+    return _tokenKind;
+}
+
 int Lexer::tokenOffset() const
 {
     return _tokenStartPtr - _code.unicode();
@@ -956,6 +1020,9 @@ QString Lexer::tokenText() const
     if (_validTokenText)
         return _tokenText;
 
+    if (_tokenKind == T_STRING_LITERAL)
+        return QString(_tokenStartPtr + 1, _tokenLength - 2);
+
     return QString(_tokenStartPtr, _tokenLength);
 }
 
@@ -987,4 +1054,113 @@ bool Lexer::prevTerminator() const
     return _terminator;
 }
 
+bool Lexer::followsClosingBrace() const
+{
+    return _followsClosingBrace;
+}
+
+bool Lexer::canInsertAutomaticSemicolon(int token) const
+{
+    return token == T_RBRACE
+            || token == EOF_SYMBOL
+            || _terminator
+            || _followsClosingBrace;
+}
+
+bool Lexer::scanDirectives(Directives *directives)
+{
+    if (_qmlMode) {
+        // the directives are a Javascript-only extension.
+        return false;
+    }
+
+    lex(); // fetch the first token
+
+    if (_tokenKind != T_DOT)
+        return true;
+
+    do {
+        lex(); // skip T_DOT
+
+        const int lineNumber = tokenStartLine();
+
+        if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD))
+            return false; // expected a valid QML/JS directive
+
+        const QString directiveName = tokenText();
+
+        if (! (directiveName == QLatin1String("pragma") ||
+               directiveName == QLatin1String("import")))
+            return false; // not a valid directive name
+
+        // it must be a pragma or an import directive.
+        if (directiveName == QLatin1String("pragma")) {
+            // .pragma library
+            if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library")))
+                return false; // expected `library
+
+            // we found a .pragma library directive
+            directives->pragmaLibrary();
+
+        } else {
+            Q_ASSERT(directiveName == QLatin1String("import"));
+            lex(); // skip .import
+
+            QString pathOrUri;
+            QString version;
+            bool fileImport = false; // file or uri import
+
+            if (_tokenKind == T_STRING_LITERAL) {
+                // .import T_STRING_LITERAL as T_IDENTIFIER
+
+                fileImport = true;
+                pathOrUri = tokenText();
+
+            } else if (_tokenKind == T_IDENTIFIER) {
+                // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER
+
+                pathOrUri = tokenText();
+
+                lex(); // skip the first T_IDENTIFIER
+                for (; _tokenKind == T_DOT; lex()) {
+                    if (lex() != T_IDENTIFIER)
+                        return false;
+
+                    pathOrUri += QLatin1Char('.');
+                    pathOrUri += tokenText();
+                }
+
+                if (_tokenKind != T_NUMERIC_LITERAL)
+                    return false; // expected the module version number
+
+                version = tokenText();
+            }
+
+            //
+            // recognize the mandatory `as' followed by the module name
+            //
+            if (! (lex() == T_RESERVED_WORD && tokenText() == QLatin1String("as")))
+                return false; // expected `as'
+
+            if (lex() != T_IDENTIFIER)
+                return false; // expected module name
+
+            const QString module = tokenText();
+
+            if (fileImport)
+                directives->importFile(pathOrUri, module);
+            else
+                directives->importModule(pathOrUri, version, module);
+        }
+
+        if (tokenStartLine() != lineNumber)
+            return false; // the directives cannot span over multiple lines
+
+        // fetch the first token after the .pragma/.import directive
+        lex();
+    } while (_tokenKind == T_DOT);
+
+    return true;
+}
+
 #include "qdeclarativejskeywords_p.h"