diff options
Diffstat (limited to 'tools/linguist/shared')
24 files changed, 1567 insertions, 7513 deletions
diff --git a/tools/linguist/shared/abstractproitemvisitor.h b/tools/linguist/shared/abstractproitemvisitor.h index cb61d06..e6031b3 100644 --- a/tools/linguist/shared/abstractproitemvisitor.h +++ b/tools/linguist/shared/abstractproitemvisitor.h @@ -49,19 +49,23 @@ QT_BEGIN_NAMESPACE struct AbstractProItemVisitor { virtual ~AbstractProItemVisitor() {} - virtual bool visitBeginProBlock(ProBlock *block) = 0; - virtual bool visitEndProBlock(ProBlock *block) = 0; - virtual bool visitBeginProVariable(ProVariable *variable) = 0; - virtual bool visitEndProVariable(ProVariable *variable) = 0; + virtual ProItem::ProItemReturn visitBeginProBlock(ProBlock *block) = 0; + virtual void visitEndProBlock(ProBlock *block) = 0; - virtual bool visitBeginProFile(ProFile *value) = 0; - virtual bool visitEndProFile(ProFile *value) = 0; + virtual ProItem::ProItemReturn visitProLoopIteration() = 0; + virtual void visitProLoopCleanup() = 0; - virtual bool visitProValue(ProValue *value) = 0; - virtual bool visitProFunction(ProFunction *function) = 0; - virtual bool visitProOperator(ProOperator *function) = 0; - virtual bool visitProCondition(ProCondition *function) = 0; + virtual void visitBeginProVariable(ProVariable *variable) = 0; + virtual void visitEndProVariable(ProVariable *variable) = 0; + + virtual ProItem::ProItemReturn visitBeginProFile(ProFile *value) = 0; + virtual ProItem::ProItemReturn visitEndProFile(ProFile *value) = 0; + + virtual void visitProValue(ProValue *value) = 0; + virtual ProItem::ProItemReturn visitProFunction(ProFunction *function) = 0; + virtual void visitProOperator(ProOperator *function) = 0; + virtual void visitProCondition(ProCondition *function) = 0; }; QT_END_NAMESPACE diff --git a/tools/linguist/shared/cpp.cpp b/tools/linguist/shared/cpp.cpp deleted file mode 100644 index 4c33e05..0000000 --- a/tools/linguist/shared/cpp.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "translator.h" - -#include <QtCore/QDebug> -#include <QtCore/QStack> -#include <QtCore/QString> -#include <QtCore/QTextCodec> -#include <QtCore/QTextStream> - -#include <ctype.h> // for isXXX() - -QT_BEGIN_NAMESPACE - -/* qmake ignore Q_OBJECT */ - -static const char MagicComment[] = "TRANSLATOR "; - -static QSet<QString> needs_Q_OBJECT; -static QSet<QString> lacks_Q_OBJECT; - -static const int yyIdentMaxLen = 128; -static const int yyCommentMaxLen = 65536; -static const int yyStringMaxLen = 65536; - -#define STRINGIFY_INTERNAL(x) #x -#define STRINGIFY(x) STRINGIFY_INTERNAL(x) -#define STRING(s) static QString str##s(QLatin1String(STRINGIFY(s))) - -//#define DIAGNOSE_RETRANSLATABILITY -/* - The first part of this source file is the C++ tokenizer. We skip - most of C++; the only tokens that interest us are defined here. - Thus, the code fragment - - int main() - { - printf("Hello, world!\n"); - return 0; - } - - is broken down into the following tokens (Tok_ omitted): - - Ident Ident LeftParen RightParen - LeftBrace - Ident LeftParen String RightParen Semicolon - return Semicolon - RightBrace. - - The 0 doesn't produce any token. -*/ - -enum { - Tok_Eof, Tok_class, Tok_namespace, Tok_return, - Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, - Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS, - Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, - Tok_Equals, - Tok_LeftBrace = 30, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, - Tok_Integer = 40, - Tok_Other -}; - -/* - The tokenizer maintains the following global variables. The names - should be self-explanatory. -*/ -static QString yyFileName; -static int yyCh; -static bool yyCodecIsUtf8; -static bool yyForceUtf8; -static QString yyIdent; -static QString yyComment; -static QString yyString; -static qlonglong yyInteger; -static QStack<int> yySavedBraceDepth; -static QStack<int> yySavedParenDepth; -static int yyBraceDepth; -static int yyParenDepth; -static int yyLineNo; -static int yyCurLineNo; -static int yyBraceLineNo; -static int yyParenLineNo; -static bool yyTokColonSeen = false; - -// the string to read from and current position in the string -static QTextCodec *yySourceCodec; -static bool yySourceIsUnicode; -static QString yyInStr; -static int yyInPos; - -static uint getChar() -{ - forever { - if (yyInPos >= yyInStr.size()) - return EOF; - uint c = yyInStr[yyInPos++].unicode(); - if (c == '\\' && yyInPos < yyInStr.size()) { - if (yyInStr[yyInPos].unicode() == '\n') { - ++yyCurLineNo; - ++yyInPos; - continue; - } - if (yyInStr[yyInPos].unicode() == '\r') { - ++yyCurLineNo; - ++yyInPos; - if (yyInPos < yyInStr.size() && yyInStr[yyInPos].unicode() == '\n') - ++yyInPos; - continue; - } - } - if (c == '\r') { - if (yyInPos < yyInStr.size() && yyInStr[yyInPos].unicode() == '\n') - ++yyInPos; - c = '\n'; - ++yyCurLineNo; - } else if (c == '\n') { - ++yyCurLineNo; - } - return c; - } -} - -static uint getToken() -{ - yyIdent.clear(); - yyComment.clear(); - yyString.clear(); - - while (yyCh != EOF) { - yyLineNo = yyCurLineNo; - - if (isalpha(yyCh) || yyCh == '_') { - do { - yyIdent += yyCh; - yyCh = getChar(); - } while (isalnum(yyCh) || yyCh == '_'); - - //qDebug() << "IDENT: " << yyIdent; - - switch (yyIdent.at(0).unicode()) { - case 'Q': - if (yyIdent == QLatin1String("Q_OBJECT")) - return Tok_Q_OBJECT; - if (yyIdent == QLatin1String("Q_DECLARE_TR_FUNCTIONS")) - return Tok_Q_DECLARE_TR_FUNCTIONS; - if (yyIdent == QLatin1String("QT_TR_NOOP")) - return Tok_tr; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP")) - return Tok_translate; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3")) - return Tok_translate; - if (yyIdent == QLatin1String("QT_TR_NOOP_UTF8")) - return Tok_trUtf8; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP_UTF8")) - return Tok_translateUtf8; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3_UTF8")) - return Tok_translateUtf8; - break; - case 'T': - // TR() for when all else fails - if (yyIdent.compare(QLatin1String("TR"), Qt::CaseInsensitive) == 0) { - return Tok_tr; - } - break; - case 'c': - if (yyIdent == QLatin1String("class")) - return Tok_class; - break; - case 'f': - /* - QTranslator::findMessage() has the same parameters as - QApplication::translate(). - */ - if (yyIdent == QLatin1String("findMessage")) - return Tok_translate; - break; - case 'n': - if (yyIdent == QLatin1String("namespace")) - return Tok_namespace; - break; - case 'r': - if (yyIdent == QLatin1String("return")) - return Tok_return; - break; - case 's': - if (yyIdent == QLatin1String("struct")) - return Tok_class; - break; - case 't': - if (yyIdent == QLatin1String("tr")) { - return Tok_tr; - } - if (yyIdent == QLatin1String("trUtf8")) { - return Tok_trUtf8; - } - if (yyIdent == QLatin1String("translate")) { - return Tok_translate; - } - } - return Tok_Ident; - } else { - switch (yyCh) { - case '#': - /* - Early versions of lupdate complained about - unbalanced braces in the following code: - - #ifdef ALPHA - while (beta) { - #else - while (gamma) { - #endif - delta; - } - - The code contains, indeed, two opening braces for - one closing brace; yet there's no reason to panic. - - The solution is to remember yyBraceDepth as it was - when #if, #ifdef or #ifndef was met, and to set - yyBraceDepth to that value when meeting #elif or - #else. - */ - do { - yyCh = getChar(); - } while (isspace(yyCh) && yyCh != '\n'); - - switch (yyCh) { - case 'i': - yyCh = getChar(); - if (yyCh == 'f') { - // if, ifdef, ifndef - yySavedBraceDepth.push(yyBraceDepth); - yySavedParenDepth.push(yyParenDepth); - } - break; - case 'e': - yyCh = getChar(); - if (yyCh == 'l') { - // elif, else - if (!yySavedBraceDepth.isEmpty()) { - yyBraceDepth = yySavedBraceDepth.top(); - yyParenDepth = yySavedParenDepth.top(); - } - } else if (yyCh == 'n') { - // endif - if (!yySavedBraceDepth.isEmpty()) { - yySavedBraceDepth.pop(); - yySavedParenDepth.pop(); - } - } - } - while (isalnum(yyCh) || yyCh == '_') - yyCh = getChar(); - break; - case '/': - yyCh = getChar(); - if (yyCh == '/') { - do { - yyCh = getChar(); - if (yyCh == EOF) - break; - yyComment.append(yyCh); - } while (yyCh != '\n'); - } else if (yyCh == '*') { - bool metAster = false; - bool metAsterSlash = false; - - while (!metAsterSlash) { - yyCh = getChar(); - if (yyCh == EOF) { - qWarning("%s: Unterminated C++ comment starting at" - " line %d\n", - qPrintable(yyFileName), yyLineNo); - return Tok_Comment; - } - yyComment.append(yyCh); - - if (yyCh == '*') - metAster = true; - else if (metAster && yyCh == '/') - metAsterSlash = true; - else - metAster = false; - } - yyCh = getChar(); - yyComment.chop(2); - } - return Tok_Comment; - case '"': - yyCh = getChar(); - while (yyCh != EOF && yyCh != '\n' && yyCh != '"') { - if (yyCh == '\\') { - yyCh = getChar(); - if (yyString.size() < yyStringMaxLen) { - yyString.append(QLatin1Char('\\')); - yyString.append(yyCh); - } - } else { - if (yyString.size() < yyStringMaxLen) - yyString.append(yyCh); - } - yyCh = getChar(); - } - - if (yyCh != '"') - qWarning("%s:%d: Unterminated C++ string", - qPrintable(yyFileName), yyLineNo); - - if (yyCh == EOF) - return Tok_Eof; - yyCh = getChar(); - return Tok_String; - case '-': - yyCh = getChar(); - if (yyCh == '>') { - yyCh = getChar(); - return Tok_Arrow; - } - break; - case ':': - yyCh = getChar(); - if (yyCh == ':') { - yyCh = getChar(); - return Tok_ColonColon; - } - return Tok_Colon; - // Incomplete: '<' might be part of '<=' or of template syntax. - // The main intent of not completely ignoring it is to break - // parsing of things like std::cout << QObject::tr() as - // context std::cout::QObject (see Task 161106) - case '=': - yyCh = getChar(); - return Tok_Equals; - case '>': - case '<': - yyCh = getChar(); - return Tok_Other; - case '\'': - yyCh = getChar(); - if (yyCh == '\\') - yyCh = getChar(); - - do { - yyCh = getChar(); - } while (yyCh != EOF && yyCh != '\''); - yyCh = getChar(); - break; - case '{': - if (yyBraceDepth == 0) - yyBraceLineNo = yyCurLineNo; - yyBraceDepth++; - yyCh = getChar(); - return Tok_LeftBrace; - case '}': - if (yyBraceDepth == 0) - yyBraceLineNo = yyCurLineNo; - yyBraceDepth--; - yyCh = getChar(); - return Tok_RightBrace; - case '(': - if (yyParenDepth == 0) - yyParenLineNo = yyCurLineNo; - yyParenDepth++; - yyCh = getChar(); - return Tok_LeftParen; - case ')': - if (yyParenDepth == 0) - yyParenLineNo = yyCurLineNo; - yyParenDepth--; - yyCh = getChar(); - return Tok_RightParen; - case ',': - yyCh = getChar(); - return Tok_Comma; - case ';': - yyCh = getChar(); - return Tok_Semicolon; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - QByteArray ba; - ba += yyCh; - yyCh = getChar(); - bool hex = yyCh == 'x'; - if (hex) { - ba += yyCh; - yyCh = getChar(); - } - while (hex ? isxdigit(yyCh) : isdigit(yyCh)) { - ba += yyCh; - yyCh = getChar(); - } - bool ok; - yyInteger = ba.toLongLong(&ok); - if (ok) - return Tok_Integer; - break; - } - default: - yyCh = getChar(); - break; - } - } - } - return Tok_Eof; -} - -/* - The second part of this source file is the parser. It accomplishes - a very easy task: It finds all strings inside a tr() or translate() - call, and possibly finds out the context of the call. It supports - three cases: (1) the context is specified, as in - FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); - (2) the call appears within an inlined function; (3) the call - appears within a function defined outside the class definition. -*/ - -static uint yyTok; - -static bool match(uint t) -{ - bool matches = (yyTok == t); - if (matches) - yyTok = getToken(); - return matches; -} - -static bool matchString(QString *s) -{ - bool matches = (yyTok == Tok_String); - s->clear(); - while (yyTok == Tok_String) { - *s += yyString; - do { - yyTok = getToken(); - } while (yyTok == Tok_Comment); - } - return matches; -} - -static bool matchEncoding(bool *utf8) -{ - STRING(QApplication); - STRING(QCoreApplication); - STRING(UnicodeUTF8); - STRING(DefaultCodec); - STRING(CodecForTr); - - if (yyTok != Tok_Ident) - return false; - if (yyIdent == strQApplication || yyIdent == strQCoreApplication) { - yyTok = getToken(); - if (yyTok == Tok_ColonColon) - yyTok = getToken(); - } - if (yyIdent == strUnicodeUTF8) { - *utf8 = true; - yyTok = getToken(); - return true; - } - if (yyIdent == strDefaultCodec || yyIdent == strCodecForTr) { - *utf8 = false; - yyTok = getToken(); - return true; - } - return false; -} - -static bool matchInteger(qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - -static bool matchStringOrNull(QString *s) -{ - bool matches = matchString(s); - qlonglong num = 0; - if (!matches) - matches = matchInteger(&num); - return matches && num == 0; -} - -/* - * match any expression that can return a number, which can be - * 1. Literal number (e.g. '11') - * 2. simple identifier (e.g. 'm_count') - * 3. simple function call (e.g. 'size()' ) - * 4. function call on an object (e.g. 'list.size()') - * 5. function call on an object (e.g. 'list->size()') - * - * Other cases: - * size(2,4) - * list().size() - * list(a,b).size(2,4) - * etc... - */ -static bool matchExpression() -{ - if (match(Tok_Integer)) - return true; - - int parenlevel = 0; - while (match(Tok_Ident) || parenlevel > 0) { - if (yyTok == Tok_RightParen) { - if (parenlevel == 0) break; - --parenlevel; - yyTok = getToken(); - } else if (yyTok == Tok_LeftParen) { - yyTok = getToken(); - if (yyTok == Tok_RightParen) { - yyTok = getToken(); - } else { - ++parenlevel; - } - } else if (yyTok == Tok_Ident) { - continue; - } else if (yyTok == Tok_Arrow) { - yyTok = getToken(); - } else if (parenlevel == 0) { - return false; - } - } - return true; -} - -static QStringList resolveNamespaces( - const QStringList &namespaces, const QHash<QString, QStringList> &namespaceAliases) -{ - static QString strColons(QLatin1String("::")); - - QStringList ns; - foreach (const QString &cns, namespaces) { - ns << cns; - ns = namespaceAliases.value(ns.join(strColons), ns); - } - return ns; -} - -static QStringList getFullyQualifiedNamespaceName( - const QSet<QString> &allNamespaces, const QStringList &namespaces, - const QHash<QString, QStringList> &namespaceAliases, - const QStringList &segments) -{ - static QString strColons(QLatin1String("::")); - - if (segments.first().isEmpty()) { - // fully qualified - QStringList segs = segments; - segs.removeFirst(); - return resolveNamespaces(segs, namespaceAliases); - } else { - for (int n = namespaces.count(); --n >= -1; ) { - QStringList ns; - for (int i = 0; i <= n; ++i) // Note: n == -1 possible - ns << namespaces[i]; - foreach (const QString &cns, segments) { - ns << cns; - ns = namespaceAliases.value(ns.join(strColons), ns); - } - if (allNamespaces.contains(ns.join(strColons))) - return ns; - } - - // Fallback when the namespace was declared in a header, etc. - QStringList ns = namespaces; - ns += segments; - return ns; - } -} - -static QString getFullyQualifiedClassName( - const QSet<QString> &allClasses, const QStringList &namespaces, - const QHash<QString, QStringList> &namespaceAliases, - const QString &ident, bool hasPrefix) -{ - static QString strColons(QLatin1String("::")); - - QString context = ident; - QStringList segments = context.split(strColons); - if (segments.first().isEmpty()) { - // fully qualified - segments.removeFirst(); - context = resolveNamespaces(segments, namespaceAliases).join(strColons); - } else { - for (int n = namespaces.count(); --n >= -1; ) { - QStringList ns; - for (int i = 0; i <= n; ++i) // Note: n == -1 possible - ns.append(namespaces[i]); - foreach (const QString &cns, segments) { - ns.append(cns); - ns = namespaceAliases.value(ns.join(strColons), ns); - } - QString nctx = ns.join(strColons); - if (allClasses.contains(nctx)) { - context = nctx; - goto gotit; - } - } - - if (!hasPrefix && namespaces.count()) - context = namespaces.join(strColons) + strColons + context; - } -gotit: - //qDebug() << "CLASSES:" << allClasses << "NAMEPACES:" << namespaces - // << "IDENT:" << ident << "CONTEXT:" << context; - return context; -} - - -static QString transcode(const QString &str, bool utf8) -{ - static const char tab[] = "abfnrtv"; - static const char backTab[] = "\a\b\f\n\r\t\v"; - const QString in = (!utf8 || yySourceIsUnicode) - ? str : QString::fromUtf8(yySourceCodec->fromUnicode(str).data()); - QString out; - - out.reserve(in.length()); - for (int i = 0; i < in.length();) { - ushort c = in[i++].unicode(); - if (c == '\\') { - if (i >= in.length()) - break; - c = in[i++].unicode(); - - if (c == '\n') - continue; - - if (c == 'x') { - QByteArray hex; - while (i < in.length() && isxdigit((c = in[i].unicode()))) { - hex += c; - i++; - } - out += hex.toUInt(0, 16); - } else if (c >= '0' && c < '8') { - QByteArray oct; - int n = 0; - oct += c; - while (n < 2 && i < in.length() && (c = in[i].unicode()) >= '0' && c < '8') { - i++; - n++; - oct += c; - } - out += oct.toUInt(0, 8); - } else { - const char *p = strchr(tab, c); - out += QChar(QLatin1Char(!p ? c : backTab[p - tab])); - } - } else { - out += c; - } - } - return out; -} - -static void recordMessage( - Translator *tor, int line, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool utf8, bool plural) -{ - TranslatorMessage msg( - transcode(context, utf8), transcode(text, utf8), transcode(comment, utf8), QString(), - yyFileName, line, QStringList(), - TranslatorMessage::Unfinished, plural); - msg.setExtraComment(transcode(extracomment.simplified(), utf8)); - if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) - msg.setUtf8(true); - tor->extend(msg); -} - -static void parse(Translator *tor, const QString &initialContext, const QString &defaultContext) -{ - static QString strColons(QLatin1String("::")); - - QMap<QString, QString> qualifiedContexts; - QSet<QString> allClasses; - QSet<QString> allNamespaces; - QHash<QString, QStringList> namespaceAliases; - QStringList namespaces; - QString context; - QString text; - QString comment; - QString extracomment; - QString functionContext = initialContext; - QString prefix; -#ifdef DIAGNOSE_RETRANSLATABILITY - QString functionName; -#endif - int line; - bool utf8 = false; - bool missing_Q_OBJECT = false; - - yyTok = getToken(); - while (yyTok != Tok_Eof) { - //qDebug() << "TOKEN: " << yyTok; - switch (yyTok) { - case Tok_class: - yyTokColonSeen = false; - /* - Partial support for inlined functions. - */ - yyTok = getToken(); - if (yyBraceDepth == namespaces.count() && yyParenDepth == 0) { - QStringList fct; - do { - /* - This code should execute only once, but we play - safe with impure definitions such as - 'class Q_EXPORT QMessageBox', in which case - 'QMessageBox' is the class name, not 'Q_EXPORT'. - */ - fct = QStringList(yyIdent); - yyTok = getToken(); - } while (yyTok == Tok_Ident); - while (yyTok == Tok_ColonColon) { - yyTok = getToken(); - if (yyTok != Tok_Ident) - break; // Oops ... - fct += yyIdent; - yyTok = getToken(); - } - functionContext = resolveNamespaces(namespaces + fct, namespaceAliases).join(strColons); - allClasses.insert(functionContext); - - if (yyTok == Tok_Colon) { - missing_Q_OBJECT = true; - // Skip any token until '{' since lupdate might do things wrong if it finds - // a '::' token here. - do { - yyTok = getToken(); - } while (yyTok != Tok_LeftBrace && yyTok != Tok_Eof); - } else { - //functionContext = defaultContext; - } - } - break; - case Tok_namespace: - yyTokColonSeen = false; - yyTok = getToken(); - if (yyTok == Tok_Ident) { - QString ns = yyIdent; - yyTok = getToken(); - if (yyTok == Tok_LeftBrace) { - if (yyBraceDepth == namespaces.count() + 1) { - namespaces.append(ns); - allNamespaces.insert(namespaces.join(strColons)); - } - } else if (yyTok == Tok_Equals) { - // e.g. namespace Is = OuterSpace::InnerSpace; - QStringList alias = namespaces; - alias.append(ns); - QStringList fullName; - yyTok = getToken(); - if (yyTok == Tok_ColonColon) - fullName.append(QString()); - while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { - if (yyTok == Tok_Ident) - fullName.append(yyIdent); - yyTok = getToken(); - } - namespaceAliases[alias.join(strColons)] = - getFullyQualifiedNamespaceName(allNamespaces, namespaces, namespaceAliases, fullName); - } - } - break; - case Tok_tr: - case Tok_trUtf8: - utf8 = (yyTok == Tok_trUtf8); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) && matchString(&text) && !text.isEmpty()) { - comment.clear(); - bool plural = false; - - if (match(Tok_RightParen)) { - // no comment - } else if (match(Tok_Comma) && matchStringOrNull(&comment)) { //comment - if (match(Tok_RightParen)) { - // ok, - } else if (match(Tok_Comma)) { - plural = true; - } - } - if (prefix.isEmpty()) { - context = functionContext; - } else { -#ifdef DIAGNOSE_RETRANSLATABILITY - int last = prefix.lastIndexOf(strColons); - QString className = prefix.mid(last == -1 ? 0 : last + 2); - if (!className.isEmpty() && className == functionName) { - qWarning("%s::%d: It is not recommended to call tr() from within a constructor '%s::%s' ", - qPrintable(yyFileName), yyLineNo, - className.constData(), functionName.constData()); - } -#endif - prefix.chop(2); - context = getFullyQualifiedClassName(allClasses, namespaces, namespaceAliases, prefix, true); - } - prefix.clear(); - if (qualifiedContexts.contains(context)) - context = qualifiedContexts[context]; - - if (!text.isEmpty()) - recordMessage(tor, line, context, text, comment, extracomment, utf8, plural); - - if (lacks_Q_OBJECT.contains(context)) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro", - qPrintable(yyFileName), yyLineNo, - qPrintable(context)); - lacks_Q_OBJECT.remove(context); - } else { - needs_Q_OBJECT.insert(context); - } - } - extracomment.clear(); - break; - case Tok_translateUtf8: - case Tok_translate: - utf8 = (yyTok == Tok_translateUtf8); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) - && matchString(&context) - && match(Tok_Comma) - && matchString(&text)) - { - comment.clear(); - bool plural = false; - if (!match(Tok_RightParen)) { - // look for comment - if (match(Tok_Comma) && matchStringOrNull(&comment)) { - if (!match(Tok_RightParen)) { - // look for encoding - if (match(Tok_Comma)) { - if (matchEncoding(&utf8)) { - if (!match(Tok_RightParen)) { - // look for the plural quantifier, - // this can be a number, an identifier or - // a function call, - // so for simplicity we mark it as plural if - // we know we have a comma instead of an - // right parentheses. - plural = match(Tok_Comma); - } - } else { - // This can be a QTranslator::translate("context", - // "source", "comment", n) plural translation - if (matchExpression() && match(Tok_RightParen)) { - plural = true; - } else { - break; - } - } - } else { - break; - } - } - } else { - break; - } - } - if (!text.isEmpty()) - recordMessage(tor, line, context, text, comment, extracomment, utf8, plural); - } - extracomment.clear(); - break; - case Tok_Q_DECLARE_TR_FUNCTIONS: - case Tok_Q_OBJECT: - missing_Q_OBJECT = false; - yyTok = getToken(); - break; - case Tok_Ident: - prefix += yyIdent; - yyTok = getToken(); - if (yyTok != Tok_ColonColon) - prefix.clear(); - break; - case Tok_Comment: - if (yyComment.startsWith(QLatin1Char(':'))) { - yyComment.remove(0, 1); - extracomment.append(yyComment); - } else { - comment = yyComment.simplified(); - if (comment.startsWith(QLatin1String(MagicComment))) { - comment.remove(0, sizeof(MagicComment) - 1); - int k = comment.indexOf(QLatin1Char(' ')); - if (k == -1) { - context = comment; - } else { - context = comment.left(k); - comment.remove(0, k + 1); - recordMessage(tor, yyLineNo, context, QString(), comment, extracomment, false, false); - } - - /* - Provide a backdoor for people using "using - namespace". See the manual for details. - */ - k = 0; - while ((k = context.indexOf(strColons, k)) != -1) { - qualifiedContexts.insert(context.mid(k + 2), context); - k++; - } - } - } - yyTok = getToken(); - break; - case Tok_Arrow: - yyTok = getToken(); - if (yyTok == Tok_tr || yyTok == Tok_trUtf8) - qWarning("%s:%d: Cannot invoke tr() like this", - qPrintable(yyFileName), yyLineNo); - break; - case Tok_ColonColon: - if (yyBraceDepth == namespaces.count() && yyParenDepth == 0 && !yyTokColonSeen) - functionContext = getFullyQualifiedClassName(allClasses, namespaces, namespaceAliases, prefix, false); - prefix += strColons; - yyTok = getToken(); -#ifdef DIAGNOSE_RETRANSLATABILITY - if (yyTok == Tok_Ident && yyBraceDepth == namespaces.count() && yyParenDepth == 0) - functionName = yyIdent; -#endif - break; - case Tok_RightBrace: - case Tok_Semicolon: - prefix.clear(); - extracomment.clear(); - yyTokColonSeen = false; - if (yyBraceDepth >= 0 && yyBraceDepth + 1 == namespaces.count()) - namespaces.removeLast(); - if (yyBraceDepth == namespaces.count()) { - if (missing_Q_OBJECT) { - if (needs_Q_OBJECT.contains(functionContext)) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro", - qPrintable(yyFileName), yyLineNo, - qPrintable(functionContext)); - } else { - lacks_Q_OBJECT.insert(functionContext); - } - } - functionContext = defaultContext; - missing_Q_OBJECT = false; - } - yyTok = getToken(); - break; - case Tok_Colon: - yyTokColonSeen = true; - yyTok = getToken(); - break; - case Tok_LeftParen: - case Tok_RightParen: - case Tok_LeftBrace: - yyTokColonSeen = false; - yyTok = getToken(); - break; - default: - yyTok = getToken(); - break; - } - } - - if (yyBraceDepth != 0) - qWarning("%s:%d: Unbalanced braces in C++ code (or abuse of the C++" - " preprocessor)\n", - qPrintable(yyFileName), yyBraceLineNo); - else if (yyParenDepth != 0) - qWarning("%s:%d: Unbalanced parentheses in C++ code (or abuse of the C++" - " preprocessor)\n", - qPrintable(yyFileName), yyParenLineNo); -} - -/* - Fetches tr() calls in C++ code in UI files (inside "<function>" - tag). This mechanism is obsolete. -*/ -void fetchtrInlinedCpp(const QString &in, Translator &translator, const QString &context) -{ - yyInStr = in; - yyInPos = 0; - yyFileName = QString(); - yyCodecIsUtf8 = (translator.codecName() == "UTF-8"); - yyForceUtf8 = true; - yySourceIsUnicode = true; - yySavedBraceDepth.clear(); - yySavedParenDepth.clear(); - yyBraceDepth = 0; - yyParenDepth = 0; - yyCurLineNo = 1; - yyBraceLineNo = 1; - yyParenLineNo = 1; - yyCh = getChar(); - - parse(&translator, context, QString()); -} - - -bool loadCPP(Translator &translator, QIODevice &dev, ConversionData &cd) -{ - QString defaultContext = cd.m_defaultContext; - - yyCodecIsUtf8 = (translator.codecName() == "UTF-8"); - yyForceUtf8 = false; - QTextStream ts(&dev); - QByteArray codecName = cd.m_codecForSource.isEmpty() - ? translator.codecName() : cd.m_codecForSource; - ts.setCodec(QTextCodec::codecForName(codecName)); - ts.setAutoDetectUnicode(true); - yySourceCodec = ts.codec(); - if (yySourceCodec->name() == "UTF-16") - translator.setCodecName("System"); - yySourceIsUnicode = yySourceCodec->name().startsWith("UTF-"); - yyInStr = ts.readAll(); - yyInPos = 0; - yyFileName = cd.m_sourceFileName; - yySavedBraceDepth.clear(); - yySavedParenDepth.clear(); - yyBraceDepth = 0; - yyParenDepth = 0; - yyCurLineNo = 1; - yyBraceLineNo = 1; - yyParenLineNo = 1; - yyCh = getChar(); - - parse(&translator, defaultContext, defaultContext); - - return true; -} - -int initCPP() -{ - Translator::FileFormat format; - format.extension = QLatin1String("cpp"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("C++ source files"); - format.loader = &loadCPP; - format.saver = 0; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initCPP) - -QT_END_NAMESPACE diff --git a/tools/linguist/shared/formats.pri b/tools/linguist/shared/formats.pri index 9c8072b..985f6db 100644 --- a/tools/linguist/shared/formats.pri +++ b/tools/linguist/shared/formats.pri @@ -19,8 +19,4 @@ SOURCES += \ $$PWD/qph.cpp \ $$PWD/po.cpp \ $$PWD/ts.cpp \ - $$PWD/ui.cpp \ - $$PWD/cpp.cpp \ - $$PWD/java.cpp \ - $$PWD/qscript.cpp \ $$PWD/xliff.cpp diff --git a/tools/linguist/shared/java.cpp b/tools/linguist/shared/java.cpp deleted file mode 100644 index d98eee6..0000000 --- a/tools/linguist/shared/java.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "translator.h" - -#include <QtCore/QDebug> -#include <QtCore/QFile> -#include <QtCore/QRegExp> -#include <QtCore/QStack> -#include <QtCore/QStack> -#include <QtCore/QString> -#include <QtCore/QTextCodec> - -#include <ctype.h> - -QT_BEGIN_NAMESPACE - -enum { Tok_Eof, Tok_class, Tok_return, Tok_tr, - Tok_translate, Tok_Ident, Tok_Package, - Tok_Comment, Tok_String, Tok_Colon, Tok_Dot, - Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, - Tok_RightParen, Tok_Comma, Tok_Semicolon, - Tok_Integer, Tok_Plus, Tok_PlusPlus, Tok_PlusEq, Tok_null }; - -class Scope -{ - public: - QString name; - enum Type {Clazz, Function, Other} type; - int line; - - Scope(const QString & name, Type type, int line) : - name(name), - type(type), - line(line) - {} - - ~Scope() - {} -}; - -/* - The tokenizer maintains the following global variables. The names - should be self-explanatory. -*/ - -static QString yyFileName; -static QChar yyCh; -static QString yyIdent; -static QString yyComment; -static QString yyString; - - -static qlonglong yyInteger; -static int yyParenDepth; -static int yyLineNo; -static int yyCurLineNo; -static int yyParenLineNo; -static int yyTok; - -// the string to read from and current position in the string -static QString yyInStr; -static int yyInPos; - -// The parser maintains the following global variables. -static QString yyPackage; -static QStack<Scope*> yyScope; -static QString yyDefaultContext; - -static QChar getChar() -{ - if (yyInPos >= yyInStr.size()) - return EOF; - QChar c = yyInStr[yyInPos++]; - if (c.unicode() == '\n') - ++yyCurLineNo; - return c.unicode(); -} - -static int getToken() -{ - const char tab[] = "bfnrt\"\'\\"; - const char backTab[] = "\b\f\n\r\t\"\'\\"; - - yyIdent.clear(); - yyComment.clear(); - yyString.clear(); - - while ( yyCh != EOF ) { - yyLineNo = yyCurLineNo; - - if ( yyCh.isLetter() || yyCh.toLatin1() == '_' ) { - do { - yyIdent.append(yyCh); - yyCh = getChar(); - } while ( yyCh.isLetterOrNumber() || yyCh.toLatin1() == '_' ); - - if (yyTok != Tok_Dot) { - switch ( yyIdent.at(0).toLatin1() ) { - case 'r': - if ( yyIdent == QLatin1String("return") ) - return Tok_return; - break; - case 'c': - if ( yyIdent == QLatin1String("class") ) - return Tok_class; - break; - case 'n': - if ( yyIdent == QLatin1String("null") ) - return Tok_null; - break; - } - } - switch ( yyIdent.at(0).toLatin1() ) { - case 'T': - // TR() for when all else fails - if ( yyIdent == QLatin1String("TR") ) - return Tok_tr; - break; - case 'p': - if( yyIdent == QLatin1String("package") ) - return Tok_Package; - break; - case 't': - if ( yyIdent == QLatin1String("tr") ) - return Tok_tr; - if ( yyIdent == QLatin1String("translate") ) - return Tok_translate; - } - return Tok_Ident; - } else { - switch ( yyCh.toLatin1() ) { - - case '/': - yyCh = getChar(); - if ( yyCh == QLatin1Char('/') ) { - do { - yyCh = getChar(); - if (yyCh == EOF) - break; - yyComment.append(yyCh); - } while (yyCh != QLatin1Char('\n')); - return Tok_Comment; - - } else if ( yyCh == QLatin1Char('*') ) { - bool metAster = false; - bool metAsterSlash = false; - - while ( !metAsterSlash ) { - yyCh = getChar(); - if ( yyCh == EOF ) { - qFatal( "%s: Unterminated Java comment starting at" - " line %d\n", - qPrintable(yyFileName), yyLineNo ); - - return Tok_Comment; - } - - yyComment.append( yyCh ); - - if ( yyCh == QLatin1Char('*') ) - metAster = true; - else if ( metAster && yyCh == QLatin1Char('/') ) - metAsterSlash = true; - else - metAster = false; - } - yyComment.chop(2); - yyCh = getChar(); - - return Tok_Comment; - } - break; - case '"': - yyCh = getChar(); - - while ( yyCh != EOF && yyCh != QLatin1Char('\n') && yyCh != QLatin1Char('"') ) { - if ( yyCh == QLatin1Char('\\') ) { - yyCh = getChar(); - if ( yyCh == QLatin1Char('u') ) { - yyCh = getChar(); - uint unicode(0); - for (int i = 4; i > 0; --i) { - unicode = unicode << 4; - if( yyCh.isDigit() ) { - unicode += yyCh.digitValue(); - } - else { - int sub(yyCh.toLower().toAscii() - 87); - if( sub > 15 || sub < 10) { - qFatal( "%s:%d: Invalid Unicode", - qPrintable(yyFileName), yyLineNo ); - } - unicode += sub; - } - yyCh = getChar(); - } - yyString.append(QChar(unicode)); - } - else if ( yyCh == QLatin1Char('\n') ) { - yyCh = getChar(); - } - else { - yyString.append( QLatin1Char(backTab[strchr( tab, yyCh.toAscii() ) - tab]) ); - yyCh = getChar(); - } - } else { - yyString.append(yyCh); - yyCh = getChar(); - } - } - - if ( yyCh != QLatin1Char('"') ) - qFatal( "%s:%d: Unterminated string", - qPrintable(yyFileName), yyLineNo ); - - yyCh = getChar(); - - return Tok_String; - - case ':': - yyCh = getChar(); - return Tok_Colon; - case '\'': - yyCh = getChar(); - - if ( yyCh == QLatin1Char('\\') ) - yyCh = getChar(); - do { - yyCh = getChar(); - } while ( yyCh != EOF && yyCh != QLatin1Char('\'') ); - yyCh = getChar(); - break; - case '{': - yyCh = getChar(); - return Tok_LeftBrace; - case '}': - yyCh = getChar(); - return Tok_RightBrace; - case '(': - if (yyParenDepth == 0) - yyParenLineNo = yyCurLineNo; - yyParenDepth++; - yyCh = getChar(); - return Tok_LeftParen; - case ')': - if (yyParenDepth == 0) - yyParenLineNo = yyCurLineNo; - yyParenDepth--; - yyCh = getChar(); - return Tok_RightParen; - case ',': - yyCh = getChar(); - return Tok_Comma; - case '.': - yyCh = getChar(); - return Tok_Dot; - case ';': - yyCh = getChar(); - return Tok_Semicolon; - case '+': - yyCh = getChar(); - if (yyCh == QLatin1Char('+')) { - yyCh = getChar(); - return Tok_PlusPlus; - } - if( yyCh == QLatin1Char('=') ){ - yyCh = getChar(); - return Tok_PlusEq; - } - return Tok_Plus; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - QByteArray ba; - ba += yyCh.toLatin1(); - yyCh = getChar(); - bool hex = yyCh == QLatin1Char('x'); - if ( hex ) { - ba += yyCh.toLatin1(); - yyCh = getChar(); - } - while ( hex ? isxdigit(yyCh.toLatin1()) : yyCh.isDigit() ) { - ba += yyCh.toLatin1(); - yyCh = getChar(); - } - bool ok; - yyInteger = ba.toLongLong(&ok); - if (ok) return Tok_Integer; - break; - } - default: - yyCh = getChar(); - } - } - } - return Tok_Eof; -} - -static bool match( int t ) -{ - bool matches = ( yyTok == t ); - if ( matches ) - yyTok = getToken(); - return matches; -} - -static bool matchString( QString &s ) -{ - if ( yyTok != Tok_String ) - return false; - - s = yyString; - yyTok = getToken(); - while ( yyTok == Tok_Plus ) { - yyTok = getToken(); - if (yyTok == Tok_String) - s += yyString; - else { - qWarning( "%s:%d: String used in translation can only contain strings" - " concatenated with other strings, not expressions or numbers.", - qPrintable(yyFileName), yyLineNo ); - return false; - } - yyTok = getToken(); - } - return true; -} - -static bool matchInteger( qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - -static bool matchStringOrNull(QString &s) -{ - bool matches = matchString(s); - if (!matches) { - matches = (yyTok == Tok_null); - if (matches) yyTok = getToken(); - } - return matches; -} - -/* - * match any expression that can return a number, which can be - * 1. Literal number (e.g. '11') - * 2. simple identifier (e.g. 'm_count') - * 3. simple function call (e.g. 'size()' ) - * 4. function call on an object (e.g. 'list.size()') - * 5. function call on an object (e.g. 'list->size()') - * - * Other cases: - * size(2,4) - * list().size() - * list(a,b).size(2,4) - * etc... - */ -static bool matchExpression() -{ - if (match(Tok_Integer)) { - return true; - } - - int parenlevel = 0; - while (match(Tok_Ident) || parenlevel > 0) { - if (yyTok == Tok_RightParen) { - if (parenlevel == 0) break; - --parenlevel; - yyTok = getToken(); - } else if (yyTok == Tok_LeftParen) { - yyTok = getToken(); - if (yyTok == Tok_RightParen) { - yyTok = getToken(); - } else { - ++parenlevel; - } - } else if (yyTok == Tok_Ident) { - continue; - } else if (parenlevel == 0) { - return false; - } - } - return true; -} - -static const QString context() -{ - QString context(yyPackage); - bool innerClass = false; - for (int i = 0; i < yyScope.size(); ++i) { - if (yyScope.at(i)->type == Scope::Clazz) { - if (innerClass) - context.append(QLatin1String("$")); - else - context.append(QLatin1String(".")); - - context.append(yyScope.at(i)->name); - innerClass = true; - } - } - return context.isEmpty() ? yyDefaultContext : context; -} - -static void recordMessage( - Translator *tor, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool plural) -{ - TranslatorMessage msg( - context, text, comment, QString(), - yyFileName, yyLineNo, QStringList(), - TranslatorMessage::Unfinished, plural); - msg.setExtraComment(extracomment.simplified()); - tor->extend(msg); -} - -static void parse( Translator *tor ) -{ - QString text; - QString com; - QString extracomment; - - yyCh = getChar(); - - yyTok = getToken(); - while ( yyTok != Tok_Eof ) { - switch ( yyTok ) { - case Tok_class: - yyTok = getToken(); - if(yyTok == Tok_Ident) { - yyScope.push(new Scope(yyIdent, Scope::Clazz, yyLineNo)); - } - else { - qFatal( "%s:%d: Class must be followed by a classname", - qPrintable(yyFileName), yyLineNo ); - } - while (!match(Tok_LeftBrace)) { - yyTok = getToken(); - } - break; - - case Tok_tr: - yyTok = getToken(); - if ( match(Tok_LeftParen) && matchString(text) ) { - com.clear(); - bool plural = false; - - if ( match(Tok_RightParen) ) { - // no comment - } else if (match(Tok_Comma) && matchStringOrNull(com)) { //comment - if ( match(Tok_RightParen)) { - // ok, - } else if (match(Tok_Comma)) { - plural = true; - } - } - if (!text.isEmpty()) - recordMessage(tor, context(), text, com, extracomment, plural); - } - break; - case Tok_translate: - { - QString contextOverride; - yyTok = getToken(); - if ( match(Tok_LeftParen) && - matchString(contextOverride) && - match(Tok_Comma) && - matchString(text) ) { - - com.clear(); - bool plural = false; - if (!match(Tok_RightParen)) { - // look for comment - if ( match(Tok_Comma) && matchStringOrNull(com)) { - if (!match(Tok_RightParen)) { - if (match(Tok_Comma) && matchExpression() && match(Tok_RightParen)) { - plural = true; - } else { - break; - } - } - } else { - break; - } - } - if (!text.isEmpty()) - recordMessage(tor, contextOverride, text, com, extracomment, plural); - } - } - break; - - case Tok_Ident: - yyTok = getToken(); - break; - - case Tok_Comment: - if (yyComment.startsWith(QLatin1Char(':'))) { - yyComment.remove(0, 1); - extracomment.append(yyComment); - } - yyTok = getToken(); - break; - - case Tok_RightBrace: - if ( yyScope.isEmpty() ) { - qFatal( "%s:%d: Unbalanced right brace in Java code\n", - qPrintable(yyFileName), yyLineNo ); - } - else - delete (yyScope.pop()); - extracomment.clear(); - yyTok = getToken(); - break; - - case Tok_LeftBrace: - yyScope.push(new Scope(QString(), Scope::Other, yyLineNo)); - yyTok = getToken(); - break; - - case Tok_Semicolon: - extracomment.clear(); - yyTok = getToken(); - break; - - case Tok_Package: - yyTok = getToken(); - while(!match(Tok_Semicolon)) { - switch(yyTok) { - case Tok_Ident: - yyPackage.append(yyIdent); - break; - case Tok_Dot: - yyPackage.append(QLatin1String(".")); - break; - default: - qFatal( "%s:%d: Package keyword should be followed by com.package.name;", - qPrintable(yyFileName), yyLineNo ); - break; - } - yyTok = getToken(); - } - break; - - default: - yyTok = getToken(); - } - } - - if ( !yyScope.isEmpty() ) - qFatal( "%s:%d: Unbalanced braces in Java code\n", - qPrintable(yyFileName), yyScope.top()->line ); - else if ( yyParenDepth != 0 ) - qFatal( "%s:%d: Unbalanced parentheses in Java code\n", - qPrintable(yyFileName), yyParenLineNo ); -} - - -bool loadJava(Translator &translator, QIODevice &dev, ConversionData &cd) -{ - //void LupdateApplication::fetchtr_java( const QString &fileName, Translator *tor, - //const QString &defaultContext, bool mustExist, const QByteArray &codecForSource ) - - yyDefaultContext = cd.m_defaultContext; - yyInPos = -1; - yyFileName = cd.m_sourceFileName; - yyPackage.clear(); - yyScope.clear(); - yyTok = -1; - yyParenDepth = 0; - yyCurLineNo = 0; - yyParenLineNo = 1; - - QTextStream ts(&dev); - QByteArray codecName; - if (!cd.m_codecForSource.isEmpty()) - codecName = cd.m_codecForSource; - else - codecName = translator.codecName(); // Just because it should be latin1 already - ts.setCodec(QTextCodec::codecForName(codecName)); - ts.setAutoDetectUnicode(true); - yyInStr = ts.readAll(); - yyInPos = 0; - yyFileName = cd.m_sourceFileName; - yyCurLineNo = 1; - yyParenLineNo = 1; - yyCh = getChar(); - - parse(&translator); - - // Java uses UTF-16 internally and Jambi makes UTF-8 for tr() purposes of it. - translator.setCodecName("UTF-8"); - return true; -} - -int initJava() -{ - Translator::FileFormat format; - format.extension = QLatin1String("java"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("Java source files"); - format.loader = &loadJava; - format.saver = 0; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initJava) - -QT_END_NAMESPACE diff --git a/tools/linguist/shared/make-qscript.sh b/tools/linguist/shared/make-qscript.sh deleted file mode 100755 index 42cab7a..0000000 --- a/tools/linguist/shared/make-qscript.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -me=$(dirname $0) -mkdir -p $me/out -(cd $me/out && ${QLALR-qlalr} --no-debug --troll --no-lines ../qscript.g) - -for f in $me/out/*.{h,cpp}; do - n=$(basename $f) - p4 open $me/../$n - cp $f $me/../$n -done - -p4 revert -a $me/../... -p4 diff -du $me/../... diff --git a/tools/linguist/shared/po.cpp b/tools/linguist/shared/po.cpp index ab5c0d2..6f06d58 100644 --- a/tools/linguist/shared/po.cpp +++ b/tools/linguist/shared/po.cpp @@ -396,7 +396,10 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) const QString prefix = QLatin1String(isObsolete ? "#~ " : ""); while (true) { int idx = line.indexOf(QLatin1Char(' '), prefix.length()); - item.msgStr.append(slurpEscapedString(lines, l, idx, prefix, cd)); + QString str = slurpEscapedString(lines, l, idx, prefix, cd); + str.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); + item.msgStr.append(str); if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1))) break; ++l; @@ -636,8 +639,11 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) out << poEscapedString(prefix, QLatin1String("msgid_plural"), noWrap, plural); const QStringList &translations = msg.translations(); for (int i = 0; i != translations.size(); ++i) { + QString str = translations.at(i); + str.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); out << poEscapedString(prefix, QString::fromLatin1("msgstr[%1]").arg(i), noWrap, - translations.at(i)); + str); } } first = false; diff --git a/tools/linguist/shared/profileevaluator.cpp b/tools/linguist/shared/profileevaluator.cpp index 7425afd..67b393c 100644 --- a/tools/linguist/shared/profileevaluator.cpp +++ b/tools/linguist/shared/profileevaluator.cpp @@ -44,6 +44,7 @@ #include "proitems.h" #include <QtCore/QByteArray> +#include <QtCore/QDateTime> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> @@ -56,6 +57,15 @@ #include <QtCore/QStringList> #include <QtCore/QTextStream> +#ifdef Q_OS_UNIX +#include <unistd.h> +#include <sys/utsname.h> +#else +#include <Windows.h> +#endif +#include <stdio.h> +#include <stdlib.h> + #ifdef Q_OS_WIN32 #define QT_POPEN _popen #define QT_PCLOSE _pclose @@ -68,6 +78,58 @@ QT_BEGIN_NAMESPACE /////////////////////////////////////////////////////////////////////// // +// Option +// +/////////////////////////////////////////////////////////////////////// + +QString +Option::fixString(QString string, uchar flags) +{ + // XXX Ripped out caching, so this will be slow. Should not matter for current uses. + + //fix the environment variables + if (flags & Option::FixEnvVars) { + int rep; + QRegExp reg_variableName(QLatin1String("\\$\\(.*\\)")); + reg_variableName.setMinimal(true); + while ((rep = reg_variableName.indexIn(string)) != -1) + string.replace(rep, reg_variableName.matchedLength(), + QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_variableName.matchedLength() - 3).toLatin1().constData()).constData())); + } + + //canonicalize it (and treat as a path) + if (flags & Option::FixPathCanonicalize) { +#if 0 + string = QFileInfo(string).canonicalFilePath(); +#endif + string = QDir::cleanPath(string); + } + + if (string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':')) + string[0] = string[0].toLower(); + + //fix separators + Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators))); + if (flags & Option::FixPathToLocalSeparators) { +#if defined(Q_OS_WIN32) + string = string.replace(QLatin1Char('/'), QLatin1Char('\\')); +#else + string = string.replace(QLatin1Char('\\'), QLatin1Char('/')); +#endif + } else if (flags & Option::FixPathToTargetSeparators) { + string = string.replace(QLatin1Char('/'), Option::dir_sep) + .replace(QLatin1Char('\\'), Option::dir_sep); + } + + if ((string.startsWith(QLatin1Char('"')) && string.endsWith(QLatin1Char('"'))) || + (string.startsWith(QLatin1Char('\'')) && string.endsWith(QLatin1Char('\'')))) + string = string.mid(1, string.length() - 2); + + return string; +} + +/////////////////////////////////////////////////////////////////////// +// // ProFileEvaluator::Private // /////////////////////////////////////////////////////////////////////// @@ -77,6 +139,12 @@ class ProFileEvaluator::Private : public AbstractProItemVisitor public: Private(ProFileEvaluator *q_); + ProFileEvaluator *q; + int m_lineNo; // Error reporting + bool m_verbose; + + /////////////// Reading pro file + bool read(ProFile *pro); ProBlock *currentBlock(); @@ -89,73 +157,126 @@ public: void leaveScope(); void finalizeBlock(); + QStack<ProBlock *> m_blockstack; + ProBlock *m_block; + + ProItem *m_commentItem; + QString m_proitem; + QString m_pendingComment; + bool m_syntaxError; + bool m_contNextLine; + bool m_inQuote; + int m_parens; + + /////////////// Evaluating pro file contents + // implementation of AbstractProItemVisitor - bool visitBeginProBlock(ProBlock *block); - bool visitEndProBlock(ProBlock *block); - bool visitBeginProVariable(ProVariable *variable); - bool visitEndProVariable(ProVariable *variable); - bool visitBeginProFile(ProFile *value); - bool visitEndProFile(ProFile *value); - bool visitProValue(ProValue *value); - bool visitProFunction(ProFunction *function); - bool visitProOperator(ProOperator *oper); - bool visitProCondition(ProCondition *condition); + ProItem::ProItemReturn visitBeginProBlock(ProBlock *block); + void visitEndProBlock(ProBlock *block); + ProItem::ProItemReturn visitProLoopIteration(); + void visitProLoopCleanup(); + void visitBeginProVariable(ProVariable *variable); + void visitEndProVariable(ProVariable *variable); + ProItem::ProItemReturn visitBeginProFile(ProFile *value); + ProItem::ProItemReturn visitEndProFile(ProFile *value); + void visitProValue(ProValue *value); + ProItem::ProItemReturn visitProFunction(ProFunction *function); + void visitProOperator(ProOperator *oper); + void visitProCondition(ProCondition *condition); QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; } QStringList values(const QString &variableName) const; QStringList values(const QString &variableName, const ProFile *pro) const; + QStringList values(const QString &variableName, const QHash<QString, QStringList> &place, + const ProFile *pro) const; QString propertyValue(const QString &val) const; bool isActiveConfig(const QString &config, bool regex = false); QStringList expandVariableReferences(const QString &value); + void doVariableReplace(QString *str); QStringList evaluateExpandFunction(const QString &function, const QString &arguments); QString format(const char *format) const; QString currentFileName() const; - QString getcwd() const; + QString currentDirectory() const; ProFile *currentProFile() const; - bool evaluateConditionalFunction(const QString &function, const QString &arguments, bool *result); - bool evaluateFile(const QString &fileName, bool *result); - bool evaluateFeatureFile(const QString &fileName, bool *result); + ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments); + bool evaluateFile(const QString &fileName); + bool evaluateFeatureFile(const QString &fileName); - QStringList qmakeFeaturePaths(); + static inline ProItem::ProItemReturn returnBool(bool b) + { return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; } - ProFileEvaluator *q; + QStringList evaluateFunction(ProBlock *funcPtr, const QStringList &argumentsList, bool *ok); - QStack<ProBlock *> m_blockstack; - ProBlock *m_block; + QStringList qmakeFeaturePaths(); - ProItem *m_commentItem; - QString m_proitem; - QString m_pendingComment; - bool m_syntaxError; - bool m_contNextLine; - bool m_condition; - bool m_invertNext; + struct State { + bool condition; + bool prevCondition; + } m_sts; + bool m_invertNext; // Short-lived, so not in State + int m_skipLevel; + bool m_cumulative; + bool m_isFirstVariableValue; QString m_lastVarName; ProVariable::VariableOperator m_variableOperator; - int m_lineNo; // Error reporting + QString m_origfile; QString m_oldPath; // To restore the current path to the path QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri' + struct ProLoop { + QString variable; + QStringList oldVarVal; + QStringList list; + int index; + bool infinite; + }; + QStack<ProLoop> m_loopStack; + + // we need the following two variables for handling + // CONFIG = foo bar $$CONFIG + QHash<QString, QStringList> m_tempValuemap; // used while evaluating (variable operator value1 value2 ...) + QHash<const ProFile*, QHash<QString, QStringList> > m_tempFilevaluemap; // used while evaluating (variable operator value1 value2 ...) QHash<QString, QStringList> m_valuemap; // VariableName must be us-ascii, the content however can be non-us-ascii. QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file QHash<QString, QString> m_properties; - QString m_origfile; + QString m_outputDir; + + bool m_definingTest; + QString m_definingFunc; + QHash<QString, ProBlock *> m_testFunctions; + QHash<QString, ProBlock *> m_replaceFunctions; + QStringList m_returnValue; + QStack<QHash<QString, QStringList> > m_valuemapStack; + QStack<QHash<const ProFile*, QHash<QString, QStringList> > > m_filevaluemapStack; int m_prevLineNo; // Checking whether we're assigning the same TARGET ProFile *m_prevProFile; // See m_prevLineNo - - bool m_verbose; }; +Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::State, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::ProLoop, Q_MOVABLE_TYPE); + ProFileEvaluator::Private::Private(ProFileEvaluator *q_) : q(q_) { + // Global parser state m_prevLineNo = 0; m_prevProFile = 0; + + // Configuration, more or less m_verbose = true; + m_cumulative = true; + + // Evaluator state + m_sts.condition = false; + m_sts.prevCondition = false; + m_invertNext = false; + m_skipLevel = 0; + m_isFirstVariableValue = true; + m_definingFunc.clear(); } bool ProFileEvaluator::Private::read(ProFile *pro) @@ -166,8 +287,11 @@ bool ProFileEvaluator::Private::read(ProFile *pro) return false; } + // Parser state m_block = 0; m_commentItem = 0; + m_inQuote = false; + m_parens = 0; m_contNextLine = false; m_syntaxError = false; m_lineNo = 1; @@ -191,71 +315,84 @@ bool ProFileEvaluator::Private::parseLine(const QString &line0) if (m_blockstack.isEmpty()) return false; - ushort quote = 0; - int parens = 0; - bool contNextLine = false; + int parens = m_parens; + bool inQuote = m_inQuote; + bool escaped = false; QString line = line0.simplified(); for (int i = 0; !m_syntaxError && i < line.length(); ++i) { ushort c = line.at(i).unicode(); - if (quote && c == quote) - quote = 0; - else if (c == '(') - ++parens; - else if (c == ')') - --parens; - else if (c == '"' && (i == 0 || line.at(i - 1).unicode() != '\\')) - quote = c; - else if (!parens && !quote) { - if (c == '#') { - insertComment(line.mid(i + 1)); - contNextLine = m_contNextLine; - break; - } - if (c == '\\' && i >= line.count() - 1) { - updateItem(); - contNextLine = true; - continue; - } - if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { - if (c == ' ') - updateItem(); - else - m_proitem += c; - continue; - } - if (c == ':') { - enterScope(false); - continue; - } - if (c == '{') { - enterScope(true); - continue; - } - if (c == '}') { - leaveScope(); + if (c == '#') { // Yep - no escaping possible + insertComment(line.mid(i + 1)); + escaped = m_contNextLine; + break; + } + if (!escaped) { + if (c == '\\') { + escaped = true; + m_proitem += c; continue; - } - if (c == '=') { - insertVariable(line, &i); + } else if (c == '"') { + inQuote = !inQuote; + m_proitem += c; continue; } - if (c == '|' || c == '!') { - insertOperator(c); - continue; + } else { + escaped = false; + } + if (!inQuote) { + if (c == '(') { + ++parens; + } else if (c == ')') { + --parens; + } else if (!parens) { + if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { + if (c == ' ') + updateItem(); + else + m_proitem += c; + continue; + } + if (c == ':') { + enterScope(false); + continue; + } + if (c == '{') { + enterScope(true); + continue; + } + if (c == '}') { + leaveScope(); + continue; + } + if (c == '=') { + insertVariable(line, &i); + continue; + } + if (c == '|' || c == '!') { + insertOperator(c); + continue; + } } } m_proitem += c; } - m_contNextLine = contNextLine; - - if (!m_syntaxError) { + m_inQuote = inQuote; + m_parens = parens; + m_contNextLine = escaped; + if (escaped) { + m_proitem.chop(1); updateItem(); - if (!m_contNextLine) + return true; + } else { + if (!m_syntaxError) { + updateItem(); finalizeBlock(); + return true; + } + return false; } - return !m_syntaxError; } void ProFileEvaluator::Private::finalizeBlock() @@ -451,85 +588,220 @@ void ProFileEvaluator::Private::updateItem() } -bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) +ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) { - if (block->blockKind() == ProBlock::ScopeKind) { - m_invertNext = false; - m_condition = false; + if (block->blockKind() & ProBlock::ScopeContentsKind) { + if (!m_definingFunc.isEmpty()) { + if (!m_skipLevel || m_cumulative) { + QHash<QString, ProBlock *> *hash = + (m_definingTest ? &m_testFunctions : &m_replaceFunctions); + if (ProBlock *def = hash->value(m_definingFunc)) + def->deref(); + hash->insert(m_definingFunc, block); + block->ref(); + block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind); + } + m_definingFunc.clear(); + return ProItem::ReturnSkip; + } else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) { + if (!m_sts.condition) + ++m_skipLevel; + else + Q_ASSERT(!m_skipLevel); + } + } else { + if (!m_skipLevel) { + if (m_sts.condition) { + m_sts.prevCondition = true; + m_sts.condition = false; + } + } else { + Q_ASSERT(!m_sts.condition); + } } - return true; + return ProItem::ReturnTrue; } -bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) +void ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) { - Q_UNUSED(block); - return true; + if ((block->blockKind() & ProBlock::ScopeContentsKind) + && !(block->blockKind() & ProBlock::FunctionBodyKind)) { + if (m_skipLevel) { + Q_ASSERT(!m_sts.condition); + --m_skipLevel; + } else if (!(block->blockKind() & ProBlock::SingleLine)) { + // Conditionals contained inside this block may have changed the state. + // So we reset it here to make an else following us do the right thing. + m_sts.condition = true; + } + } +} + +ProItem::ProItemReturn ProFileEvaluator::Private::visitProLoopIteration() +{ + ProLoop &loop = m_loopStack.top(); + + if (loop.infinite) { + if (!loop.variable.isEmpty()) + m_valuemap[loop.variable] = QStringList(QString::number(loop.index++)); + if (loop.index > 1000) { + q->errorMessage(format("ran into infinite loop (> 1000 iterations).")); + return ProItem::ReturnFalse; + } + } else { + QString val; + do { + if (loop.index >= loop.list.count()) + return ProItem::ReturnFalse; + val = loop.list.at(loop.index++); + } while (val.isEmpty()); // stupid, but qmake is like that + m_valuemap[loop.variable] = QStringList(val); + } + return ProItem::ReturnTrue; +} + +void ProFileEvaluator::Private::visitProLoopCleanup() +{ + ProLoop &loop = m_loopStack.top(); + m_valuemap[loop.variable] = loop.oldVarVal; + m_loopStack.pop_back(); } -bool ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable) +void ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable) { m_lastVarName = variable->variable(); m_variableOperator = variable->variableOperator(); - return true; + m_isFirstVariableValue = true; + m_tempValuemap = m_valuemap; + m_tempFilevaluemap = m_filevaluemap; } -bool ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable) +void ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable) { Q_UNUSED(variable); + m_valuemap = m_tempValuemap; + m_filevaluemap = m_tempFilevaluemap; m_lastVarName.clear(); - return true; } -bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper) +void ProFileEvaluator::Private::visitProOperator(ProOperator *oper) { m_invertNext = (oper->operatorKind() == ProOperator::NotOperator); - return true; } -bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond) +void ProFileEvaluator::Private::visitProCondition(ProCondition *cond) { - if (!m_condition) { - if (m_invertNext) - m_condition |= !isActiveConfig(cond->text(), true); - else - m_condition |= isActiveConfig(cond->text(), true); + if (!m_skipLevel) { + if (!cond->text().compare(QLatin1String("else"), Qt::CaseInsensitive)) { + m_sts.condition = !m_sts.prevCondition; + } else { + m_sts.prevCondition = false; + if (!m_sts.condition && isActiveConfig(cond->text(), true) ^ m_invertNext) + m_sts.condition = true; + } } - return true; + m_invertNext = false; } -bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) +ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) { PRE(pro); - bool ok = true; m_lineNo = pro->lineNumber(); + if (m_origfile.isEmpty()) + m_origfile = pro->fileName(); if (m_oldPath.isEmpty()) { // change the working directory for the initial profile we visit, since // that is *the* profile. All the other times we reach this function will be due to // include(file) or load(file) + m_oldPath = QDir::currentPath(); + m_profileStack.push(pro); - ok = QDir::setCurrent(pro->directoryName()); - } - if (m_origfile.isEmpty()) - m_origfile = pro->fileName(); + const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); + if (!mkspecDirectory.isEmpty()) { + bool cumulative = m_cumulative; + m_cumulative = false; + // This is what qmake does, everything set in the mkspec is also set + // But this also creates a lot of problems + evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf")); + evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf")); + m_cumulative = cumulative; + } - return ok; + return returnBool(QDir::setCurrent(pro->directoryName())); + } + + return ProItem::ReturnTrue; } -bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) +ProItem::ProItemReturn ProFileEvaluator::Private::visitEndProFile(ProFile * pro) { PRE(pro); - bool ok = true; m_lineNo = pro->lineNumber(); if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) { + const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); + if (!mkspecDirectory.isEmpty()) { + bool cumulative = m_cumulative; + m_cumulative = false; + + evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf")); + + QSet<QString> processed; + forever { + bool finished = true; + QStringList configs = valuesDirect(QLatin1String("CONFIG")); + for (int i = configs.size() - 1; i >= 0; --i) { + const QString config = configs[i].toLower(); + if (!processed.contains(config)) { + processed.insert(config); + if (evaluateFile(mkspecDirectory + QLatin1String("/features/") + + config + QLatin1String(".prf"))) { + finished = false; + break; + } + } + } + if (finished) + break; + } + + foreach (ProBlock *itm, m_replaceFunctions) + itm->deref(); + m_replaceFunctions.clear(); + foreach (ProBlock *itm, m_testFunctions) + itm->deref(); + m_testFunctions.clear(); + + m_cumulative = cumulative; + } + m_profileStack.pop(); - ok = QDir::setCurrent(m_oldPath); + return returnBool(QDir::setCurrent(m_oldPath)); + } + + return ProItem::ReturnTrue; +} + +static void replaceInList(QStringList *varlist, + const QRegExp ®exp, const QString &replace, bool global) +{ + for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) { + if ((*varit).contains(regexp)) { + (*varit).replace(regexp, replace); + if ((*varit).isEmpty()) + varit = varlist->erase(varit); + else + ++varit; + if(!global) + break; + } else { + ++varit; + } } - return ok; } -bool ProFileEvaluator::Private::visitProValue(ProValue *value) +void ProFileEvaluator::Private::visitProValue(ProValue *value) { PRE(value); m_lineNo = value->lineNumber(); @@ -546,8 +818,8 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) if (varName == QLatin1String("TARGET") && m_lineNo == m_prevLineNo && currentProFile() == m_prevProFile) { - QStringList targets = m_valuemap.value(QLatin1String("TARGET")); - m_valuemap.remove(QLatin1String("TARGET")); + QStringList targets = m_tempValuemap.value(QLatin1String("TARGET")); + m_tempValuemap.remove(QLatin1String("TARGET")); QStringList lastTarget(targets.takeLast()); lastTarget << v.join(QLatin1String(" ")); targets.push_back(lastTarget.join(QLatin1String(" "))); @@ -557,38 +829,59 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) m_prevProFile = currentProFile(); switch (m_variableOperator) { - case ProVariable::UniqueAddOperator: // * - insertUnique(&m_valuemap, varName, v, true); - insertUnique(&m_filevaluemap[currentProFile()], varName, v, true); - break; case ProVariable::SetOperator: // = - case ProVariable::AddOperator: // + - insertUnique(&m_valuemap, varName, v, false); - insertUnique(&m_filevaluemap[currentProFile()], varName, v, false); + if (!m_cumulative) { + if (!m_skipLevel) { + if (m_isFirstVariableValue) { + m_tempValuemap[varName] = v; + m_tempFilevaluemap[currentProFile()][varName] = v; + } else { // handle lines "CONFIG = foo bar" + m_tempValuemap[varName] += v; + m_tempFilevaluemap[currentProFile()][varName] += v; + } + } + } else { + // We are greedy for values. + m_tempValuemap[varName] += v; + m_tempFilevaluemap[currentProFile()][varName] += v; + } + break; + case ProVariable::UniqueAddOperator: // *= + if (!m_skipLevel || m_cumulative) { + insertUnique(&m_tempValuemap, varName, v); + insertUnique(&m_tempFilevaluemap[currentProFile()], varName, v); + } break; - case ProVariable::RemoveOperator: // - - // fix me: interaction between AddOperator and RemoveOperator - insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false); - insertUnique(&m_filevaluemap[currentProFile()], - varName.prepend(QLatin1Char('-')), v, false); + case ProVariable::AddOperator: // += + if (!m_skipLevel || m_cumulative) { + m_tempValuemap[varName] += v; + m_tempFilevaluemap[currentProFile()][varName] += v; + } break; - case ProVariable::ReplaceOperator: // ~ + case ProVariable::RemoveOperator: // -= + if (!m_cumulative) { + if (!m_skipLevel) { + removeEach(&m_tempValuemap, varName, v); + removeEach(&m_tempFilevaluemap[currentProFile()], varName, v); + } + } else { + // We are stingy with our values, too. + } + break; + case ProVariable::ReplaceOperator: // ~= { // DEFINES ~= s/a/b/?[gqi] -/* Create a superset by executing replacement + adding items that have changed - to original list. We're not sure if this is really the right approach, so for - the time being we will just do nothing ... - + doVariableReplace(&val); + if (val.length() < 4 || val[0] != QLatin1Char('s')) { + q->logMessage(format("the ~= operator can handle only the s/// function.")); + break; + } QChar sep = val.at(1); QStringList func = val.split(sep); if (func.count() < 3 || func.count() > 4) { - q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments.")); - return false; - } - if (func[0] != QLatin1String("s")) { - q->logMessage(format("~= operator can only handle s/// function.")); - return false; + q->logMessage(format("the s/// function expects 3 or 4 arguments.")); + break; } bool global = false, quote = false, case_sense = false; @@ -604,40 +897,41 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive); - QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace, - global); - // Add changed entries to list - foreach (const QString &entry, replaceList) - if (!m_valuemap.value(varName).contains(entry)) - insertUnique(&m_valuemap, varName, QStringList() << entry, false); - - replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp, - replace, global); - foreach (const QString &entry, replaceList) - if (!m_filevaluemap[currentProFile()].value(varName).contains(entry)) - insertUnique(&m_filevaluemap[currentProFile()], varName, - QStringList() << entry, false); */ + if (!m_skipLevel || m_cumulative) { + // We could make a union of modified and unmodified values, + // but this will break just as much as it fixes, so leave it as is. + replaceInList(&m_tempValuemap[varName], regexp, replace, global); + replaceInList(&m_tempFilevaluemap[currentProFile()][varName], regexp, replace, global); + } } break; } - return true; + m_isFirstVariableValue = false; } -bool ProFileEvaluator::Private::visitProFunction(ProFunction *func) +ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func) { - m_lineNo = func->lineNumber(); - bool result = true; - bool ok = true; - QString text = func->text(); - int lparen = text.indexOf(QLatin1Char('(')); - int rparen = text.lastIndexOf(QLatin1Char(')')); - Q_ASSERT(lparen < rparen); - - QString arguments = text.mid(lparen + 1, rparen - lparen - 1); - QString funcName = text.left(lparen); - ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result); - return ok; + // Make sure that called subblocks don't inherit & destroy the state + bool invertThis = m_invertNext; + m_invertNext = false; + if (!m_skipLevel) + m_sts.prevCondition = false; + if (m_cumulative || !m_sts.condition) { + QString text = func->text(); + int lparen = text.indexOf(QLatin1Char('(')); + int rparen = text.lastIndexOf(QLatin1Char(')')); + Q_ASSERT(lparen < rparen); + QString arguments = text.mid(lparen + 1, rparen - lparen - 1); + QString funcName = text.left(lparen); + m_lineNo = func->lineNumber(); + ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments); + if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue) + return result; + if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis)) + m_sts.condition = true; + } + return ProItem::ReturnTrue; } @@ -645,7 +939,7 @@ QStringList ProFileEvaluator::Private::qmakeFeaturePaths() { QStringList concat; { - const QString base_concat = QDir::separator() + QString(QLatin1String("features")); + const QString base_concat = QDir::separator() + QLatin1String("features"); concat << base_concat + QDir::separator() + QLatin1String("mac"); concat << base_concat + QDir::separator() + QLatin1String("macx"); concat << base_concat + QDir::separator() + QLatin1String("unix"); @@ -654,7 +948,7 @@ QStringList ProFileEvaluator::Private::qmakeFeaturePaths() concat << base_concat + QDir::separator() + QLatin1String("qnx6"); concat << base_concat; } - const QString mkspecs_concat = QDir::separator() + QString(QLatin1String("mkspecs")); + const QString mkspecs_concat = QDir::separator() + QLatin1String("mkspecs"); QStringList feature_roots; QByteArray mkspec_path = qgetenv("QMAKEFEATURES"); if (!mkspec_path.isNull()) @@ -757,12 +1051,17 @@ QString ProFileEvaluator::Private::currentFileName() const return QString(); } -QString ProFileEvaluator::Private::getcwd() const +QString ProFileEvaluator::Private::currentDirectory() const { ProFile *cur = m_profileStack.top(); return cur->directoryName(); } +void ProFileEvaluator::Private::doVariableReplace(QString *str) +{ + *str = expandVariableReferences(*str).join(QString(Option::field_sep)); +} + QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &str) { QStringList ret; @@ -977,10 +1276,49 @@ bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex return false; } +QStringList ProFileEvaluator::Private::evaluateFunction( + ProBlock *funcPtr, const QStringList &argumentsList, bool *ok) +{ + bool oki; + QStringList ret; + + if (m_valuemapStack.count() >= 100) { + q->errorMessage(format("ran into infinite recursion (depth > 100).")); + oki = false; + } else { + State sts = m_sts; + m_valuemapStack.push(m_valuemap); + m_filevaluemapStack.push(m_filevaluemap); + + QStringList args; + for (int i = 0; i < argumentsList.count(); ++i) { + QStringList theArgs = expandVariableReferences(argumentsList[i]); + args += theArgs; + m_valuemap[QString::number(i+1)] = theArgs; + } + m_valuemap[QLatin1String("ARGS")] = args; + oki = (funcPtr->Accept(this) != ProItem::ReturnFalse); // True || Return + ret = m_returnValue; + m_returnValue.clear(); + + m_valuemap = m_valuemapStack.pop(); + m_filevaluemap = m_filevaluemapStack.pop(); + m_sts = sts; + } + if (ok) + *ok = oki; + if (oki) + return ret; + return QStringList(); +} + QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments) { QStringList argumentsList = split_arg_list(arguments); + if (ProBlock *funcPtr = m_replaceFunctions.value(func, 0)) + return evaluateFunction(funcPtr, argumentsList, 0); + QStringList args; for (int i = 0; i < argumentsList.count(); ++i) args += expandVariableReferences(argumentsList[i]).join(Option::field_sep); @@ -991,35 +1329,34 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE }; - static QHash<QString, int> *expands = 0; - if (!expands) { - expands = new QHash<QString, int>; - expands->insert(QLatin1String("member"), E_MEMBER); //v (implemented) - expands->insert(QLatin1String("first"), E_FIRST); //v - expands->insert(QLatin1String("last"), E_LAST); //v - expands->insert(QLatin1String("cat"), E_CAT); - expands->insert(QLatin1String("fromfile"), E_FROMFILE); - expands->insert(QLatin1String("eval"), E_EVAL); - expands->insert(QLatin1String("list"), E_LIST); - expands->insert(QLatin1String("sprintf"), E_SPRINTF); - expands->insert(QLatin1String("join"), E_JOIN); //v - expands->insert(QLatin1String("split"), E_SPLIT); //v - expands->insert(QLatin1String("basename"), E_BASENAME); //v - expands->insert(QLatin1String("dirname"), E_DIRNAME); //v - expands->insert(QLatin1String("section"), E_SECTION); - expands->insert(QLatin1String("find"), E_FIND); - expands->insert(QLatin1String("system"), E_SYSTEM); //v - expands->insert(QLatin1String("unique"), E_UNIQUE); - expands->insert(QLatin1String("quote"), E_QUOTE); //v - expands->insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND); - expands->insert(QLatin1String("upper"), E_UPPER); - expands->insert(QLatin1String("lower"), E_LOWER); - expands->insert(QLatin1String("re_escape"), E_RE_ESCAPE); - expands->insert(QLatin1String("files"), E_FILES); - expands->insert(QLatin1String("prompt"), E_PROMPT); - expands->insert(QLatin1String("replace"), E_REPLACE); + static QHash<QString, int> expands; + if (expands.isEmpty()) { + expands.insert(QLatin1String("member"), E_MEMBER); + expands.insert(QLatin1String("first"), E_FIRST); + expands.insert(QLatin1String("last"), E_LAST); + expands.insert(QLatin1String("cat"), E_CAT); + expands.insert(QLatin1String("fromfile"), E_FROMFILE); // implementation disabled (see comment below) + expands.insert(QLatin1String("eval"), E_EVAL); + expands.insert(QLatin1String("list"), E_LIST); + expands.insert(QLatin1String("sprintf"), E_SPRINTF); + expands.insert(QLatin1String("join"), E_JOIN); + expands.insert(QLatin1String("split"), E_SPLIT); + expands.insert(QLatin1String("basename"), E_BASENAME); + expands.insert(QLatin1String("dirname"), E_DIRNAME); + expands.insert(QLatin1String("section"), E_SECTION); + expands.insert(QLatin1String("find"), E_FIND); + expands.insert(QLatin1String("system"), E_SYSTEM); + expands.insert(QLatin1String("unique"), E_UNIQUE); + expands.insert(QLatin1String("quote"), E_QUOTE); + expands.insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND); + expands.insert(QLatin1String("upper"), E_UPPER); + expands.insert(QLatin1String("lower"), E_LOWER); + expands.insert(QLatin1String("re_escape"), E_RE_ESCAPE); + expands.insert(QLatin1String("files"), E_FILES); + expands.insert(QLatin1String("prompt"), E_PROMPT); // interactive, so cannot be implemented + expands.insert(QLatin1String("replace"), E_REPLACE); } - ExpandFunc func_t = ExpandFunc(expands->value(func.toLower())); + ExpandFunc func_t = ExpandFunc(expands.value(func.toLower())); QStringList ret; @@ -1065,6 +1402,16 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun } break; } + case E_SPRINTF: + if(args.count() < 1) { + q->logMessage(format("sprintf(format, ...) requires at least one argument")); + } else { + QString tmp = args.at(0); + for (int i = 1; i < args.count(); ++i) + tmp = tmp.arg(args.at(i)); + ret = split_value_list(tmp); + } + break; case E_JOIN: { if (args.count() < 1 || args.count() > 4) { q->logMessage(format("join(var, glue, before, after) requires one to four arguments.")); @@ -1084,9 +1431,9 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun } case E_SPLIT: { if (args.count() != 2) { - q->logMessage(format("split(var, sep) requires two arguments")); + q->logMessage(format("split(var, sep) requires one or two arguments")); } else { - QString sep = args.at(1); + const QString &sep = (args.count() == 2) ? args[1] : QString(Option::field_sep); foreach (const QString &var, values(args.first())) foreach (const QString &splt, var.split(sep)) ret.append(splt); @@ -1157,8 +1504,82 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun } break; } - case E_SYSTEM: { - if (m_condition) { + case E_CAT: + if (args.count() < 1 || args.count() > 2) { + q->logMessage(format("cat(file, singleline=true) requires one or two arguments.")); + } else { + QString file = args[0]; + file = Option::fixPathToLocalOS(file); + + bool singleLine = true; + if (args.count() > 1) + singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive)); + + QFile qfile(file); + if (qfile.open(QIODevice::ReadOnly)) { + QTextStream stream(&qfile); + while (!stream.atEnd()) { + ret += split_value_list(stream.readLine().trimmed()); + if (!singleLine) + ret += QLatin1String("\n"); + } + qfile.close(); + } + } + break; +#if 0 // Used only by Qt's configure for caching + case E_FROMFILE: + if (args.count() != 2) { + q->logMessage(format("fromfile(file, variable) requires two arguments.")); + } else { + QString file = args[0], seek_variableName = args[1]; + + ProFile pro(Option::fixPathToLocalOS(file)); + + ProFileEvaluator visitor; + visitor.setVerbose(m_verbose); + visitor.setCumulative(m_cumulative); + + if (!visitor.queryProFile(&pro)) + break; + + if (!visitor.accept(&pro)) + break; + + ret = visitor.values(seek_variableName); + } + break; +#endif + case E_EVAL: { + if (args.count() != 1) { + q->logMessage(format("eval(variable) requires one argument")); + + } else { + ret += values(args.at(0)); + } + break; } + case E_LIST: { + static int x = 0; + QString tmp; + tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", x++); + ret = QStringList(tmp); + QStringList lst; + foreach (const QString &arg, args) + lst += split_value_list(arg); + m_valuemap[tmp] = lst; + break; } + case E_FIND: + if (args.count() != 2) { + q->logMessage(format("find(var, str) requires two arguments.")); + } else { + QRegExp regx(args[1]); + foreach (const QString &val, values(args.first())) + if (regx.indexIn(val) != -1) + ret += val; + } + break; + case E_SYSTEM: + if (!m_skipLevel) { if (args.count() < 1 || args.count() > 2) { q->logMessage(format("system(execute) requires one or two arguments.")); } else { @@ -1166,7 +1587,7 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun FILE *proc = QT_POPEN(args[0].toLatin1(), "r"); bool singleLine = true; if (args.count() > 1) - singleLine = (args[1].toLower() == QLatin1String("true")); + singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive)); QString output; while (proc && !feof(proc)) { int read_in = int(fread(buff, 1, 255, proc)); @@ -1184,13 +1605,114 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun QT_PCLOSE(proc); } } - break; } + break; + case E_UNIQUE: + if(args.count() != 1) { + q->logMessage(format("unique(var) requires one argument.")); + } else { + foreach (const QString &var, values(args.first())) + if (!ret.contains(var)) + ret.append(var); + } + break; case E_QUOTE: for (int i = 0; i < args.count(); ++i) ret += QStringList(args.at(i)); break; + case E_ESCAPE_EXPAND: + for (int i = 0; i < args.size(); ++i) { + QChar *i_data = args[i].data(); + int i_len = args[i].length(); + for (int x = 0; x < i_len; ++x) { + if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) { + if (*(i_data+x+1) == QLatin1Char('\\')) { + ++x; + } else { + struct { + char in, out; + } mapped_quotes[] = { + { 'n', '\n' }, + { 't', '\t' }, + { 'r', '\r' }, + { 0, 0 } + }; + for (int i = 0; mapped_quotes[i].in; ++i) { + if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) { + *(i_data+x) = QLatin1Char(mapped_quotes[i].out); + if (x < i_len-2) + memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar)); + --i_len; + break; + } + } + } + } + } + ret.append(QString(i_data, i_len)); + } + break; + case E_RE_ESCAPE: + for (int i = 0; i < args.size(); ++i) + ret += QRegExp::escape(args[i]); + break; + case E_UPPER: + case E_LOWER: + for (int i = 0; i < args.count(); ++i) + if (func_t == E_UPPER) + ret += args[i].toUpper(); + else + ret += args[i].toLower(); + break; + case E_FILES: + if (args.count() != 1 && args.count() != 2) { + q->logMessage(format("files(pattern, recursive=false) requires one or two arguments")); + } else { + bool recursive = false; + if (args.count() == 2) + recursive = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive) || args[1].toInt()); + QStringList dirs; + QString r = Option::fixPathToLocalOS(args[0]); + int slash = r.lastIndexOf(QDir::separator()); + if (slash != -1) { + dirs.append(r.left(slash)); + r = r.mid(slash+1); + } else { + dirs.append(QString()); + } + + const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard); + for (int d = 0; d < dirs.count(); d++) { + QString dir = dirs[d]; + if (!dir.isEmpty() && !dir.endsWith(Option::dir_sep)) + dir += QLatin1Char('/'); + + QDir qdir(dir); + for (int i = 0; i < (int)qdir.count(); ++i) { + if (qdir[i] == QLatin1String(".") || qdir[i] == QLatin1String("..")) + continue; + QString fname = dir + qdir[i]; + if (QFileInfo(fname).isDir()) { + if (recursive) + dirs.append(fname); + } + if (regex.exactMatch(qdir[i])) + ret += fname; + } + } + } + break; + case E_REPLACE: + if(args.count() != 3 ) { + q->logMessage(format("replace(var, before, after) requires three arguments")); + } else { + const QRegExp before(args[1]); + const QString after(args[2]); + foreach (QString val, values(args.first())) + ret += val.replace(before, after); + } + break; case 0: - q->logMessage(format("'%1' is not a function").arg(func)); + q->logMessage(format("'%1' is not a recognized replace function").arg(func)); break; default: q->logMessage(format("Function '%1' is not implemented").arg(func)); @@ -1200,64 +1722,323 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun return ret; } -bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &function, - const QString &arguments, bool *result) +ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction( + const QString &function, const QString &arguments) { QStringList argumentsList = split_arg_list(arguments); + + if (ProBlock *funcPtr = m_testFunctions.value(function, 0)) { + bool ok; + QStringList ret = evaluateFunction(funcPtr, argumentsList, &ok); + if (ok) { + if (ret.isEmpty()) { + return ProItem::ReturnTrue; + } else { + if (ret.first() != QLatin1String("false")) { + if (ret.first() == QLatin1String("true")) { + return ProItem::ReturnTrue; + } else { + bool ok; + int val = ret.first().toInt(&ok); + if (ok) { + if (val) + return ProItem::ReturnTrue; + } else { + q->logMessage(format("Unexpected return value from test '%1': %2") + .arg(function).arg(ret.join(QLatin1String(" :: ")))); + } + } + } + } + } + return ProItem::ReturnFalse; + } + QString sep; sep.append(Option::field_sep); - QStringList args; for (int i = 0; i < argumentsList.count(); ++i) args += expandVariableReferences(argumentsList[i]).join(sep); - enum ConditionFunc { CF_CONFIG = 1, CF_CONTAINS, CF_COUNT, CF_EXISTS, CF_INCLUDE, - CF_LOAD, CF_ISEMPTY, CF_SYSTEM, CF_MESSAGE}; - - static QHash<QString, int> *functions = 0; - if (!functions) { - functions = new QHash<QString, int>; - functions->insert(QLatin1String("load"), CF_LOAD); //v - functions->insert(QLatin1String("include"), CF_INCLUDE); //v - functions->insert(QLatin1String("message"), CF_MESSAGE); //v - functions->insert(QLatin1String("warning"), CF_MESSAGE); //v - functions->insert(QLatin1String("error"), CF_MESSAGE); //v + enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, + T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, + T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE, + T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF, + T_FOR, T_DEFINE_TEST, T_DEFINE_REPLACE }; + + static QHash<QString, int> functions; + if (functions.isEmpty()) { + functions.insert(QLatin1String("requires"), T_REQUIRES); + functions.insert(QLatin1String("greaterThan"), T_GREATERTHAN); + functions.insert(QLatin1String("lessThan"), T_LESSTHAN); + functions.insert(QLatin1String("equals"), T_EQUALS); + functions.insert(QLatin1String("isEqual"), T_EQUALS); + functions.insert(QLatin1String("exists"), T_EXISTS); + functions.insert(QLatin1String("export"), T_EXPORT); + functions.insert(QLatin1String("clear"), T_CLEAR); + functions.insert(QLatin1String("unset"), T_UNSET); + functions.insert(QLatin1String("eval"), T_EVAL); + functions.insert(QLatin1String("CONFIG"), T_CONFIG); + functions.insert(QLatin1String("if"), T_IF); + functions.insert(QLatin1String("isActiveConfig"), T_CONFIG); + functions.insert(QLatin1String("system"), T_SYSTEM); + functions.insert(QLatin1String("return"), T_RETURN); + functions.insert(QLatin1String("break"), T_BREAK); + functions.insert(QLatin1String("next"), T_NEXT); + functions.insert(QLatin1String("defined"), T_DEFINED); + functions.insert(QLatin1String("contains"), T_CONTAINS); + functions.insert(QLatin1String("infile"), T_INFILE); + functions.insert(QLatin1String("count"), T_COUNT); + functions.insert(QLatin1String("isEmpty"), T_ISEMPTY); + functions.insert(QLatin1String("load"), T_LOAD); //v + functions.insert(QLatin1String("include"), T_INCLUDE); //v + functions.insert(QLatin1String("debug"), T_DEBUG); + functions.insert(QLatin1String("message"), T_MESSAGE); //v + functions.insert(QLatin1String("warning"), T_MESSAGE); //v + functions.insert(QLatin1String("error"), T_MESSAGE); //v + functions.insert(QLatin1String("for"), T_FOR); //v + functions.insert(QLatin1String("defineTest"), T_DEFINE_TEST); //v + functions.insert(QLatin1String("defineReplace"), T_DEFINE_REPLACE); //v } - bool cond = false; - bool ok = true; - - ConditionFunc func_t = (ConditionFunc)functions->value(function); + TestFunc func_t = (TestFunc)functions.value(function); switch (func_t) { - case CF_CONFIG: { + case T_DEFINE_TEST: + m_definingTest = true; + goto defineFunc; + case T_DEFINE_REPLACE: + m_definingTest = false; + defineFunc: + if (args.count() != 1) { + q->logMessage(format("%s(function) requires one argument.").arg(function)); + return ProItem::ReturnFalse; + } + m_definingFunc = args.first(); + return ProItem::ReturnTrue; + case T_DEFINED: + if (args.count() < 1 || args.count() > 2) { + q->logMessage(format("defined(function, [\"test\"|\"replace\"])" + " requires one or two arguments.")); + return ProItem::ReturnFalse; + } + if (args.count() > 1) { + if (args[1] == QLatin1String("test")) + return returnBool(m_testFunctions.contains(args[0])); + else if (args[1] == QLatin1String("replace")) + return returnBool(m_replaceFunctions.contains(args[0])); + q->logMessage(format("defined(function, type):" + " unexpected type [%1].\n").arg(args[1])); + return ProItem::ReturnFalse; + } + return returnBool(m_replaceFunctions.contains(args[0]) + || m_testFunctions.contains(args[0])); + case T_RETURN: + m_returnValue = args; + // It is "safe" to ignore returns - due to qmake brokeness + // they cannot be used to terminate loops anyway. + if (m_skipLevel || m_cumulative) + return ProItem::ReturnTrue; + if (m_valuemapStack.isEmpty()) { + q->logMessage(format("unexpected return().")); + return ProItem::ReturnFalse; + } + return ProItem::ReturnReturn; + case T_EXPORT: + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnTrue; + if (args.count() != 1) { + q->logMessage(format("export(variable) requires one argument.")); + return ProItem::ReturnFalse; + } + for (int i = 0; i < m_valuemapStack.size(); ++i) { + m_valuemapStack[i][args[0]] = m_valuemap[args[0]]; + m_filevaluemapStack[i][currentProFile()][args[0]] = + m_filevaluemap[currentProFile()][args[0]]; + } + return ProItem::ReturnTrue; +#if 0 + case T_INFILE: + case T_REQUIRES: + case T_EVAL: +#endif + case T_FOR: { + if (m_cumulative) // This is a no-win situation, so just pretend it's no loop + return ProItem::ReturnTrue; + if (m_skipLevel) + return ProItem::ReturnFalse; + if (args.count() > 2 || args.count() < 1) { + q->logMessage(format("for({var, list|var, forever|ever})" + " requires one or two arguments.")); + return ProItem::ReturnFalse; + } + ProLoop loop; + loop.infinite = false; + loop.index = 0; + QString it_list; + if (args.count() == 1) { + doVariableReplace(&args[0]); + it_list = args[0]; + if (args[0] != QLatin1String("ever")) { + q->logMessage(format("for({var, list|var, forever|ever})" + " requires one or two arguments.")); + return ProItem::ReturnFalse; + } + it_list = QLatin1String("forever"); + } else { + loop.variable = args[0]; + loop.oldVarVal = m_valuemap.value(loop.variable); + doVariableReplace(&args[1]); + it_list = args[1]; + } + loop.list = m_valuemap[it_list]; + if (loop.list.isEmpty()) { + if (it_list == QLatin1String("forever")) { + loop.infinite = true; + } else { + int dotdot = it_list.indexOf(QLatin1String("..")); + if (dotdot != -1) { + bool ok; + int start = it_list.left(dotdot).toInt(&ok); + if (ok) { + int end = it_list.mid(dotdot+2).toInt(&ok); + if (ok) { + if (start < end) { + for (int i = start; i <= end; i++) + loop.list << QString::number(i); + } else { + for (int i = start; i >= end; i--) + loop.list << QString::number(i); + } + } + } + } + } + } + m_loopStack.push(loop); + m_sts.condition = true; + return ProItem::ReturnLoop; + } + case T_BREAK: + if (m_skipLevel) + return ProItem::ReturnFalse; + if (!m_loopStack.isEmpty()) + return ProItem::ReturnBreak; + // ### missing: breaking out of multiline blocks + q->logMessage(format("unexpected break().")); + return ProItem::ReturnFalse; + case T_NEXT: + if (m_skipLevel) + return ProItem::ReturnFalse; + if (!m_loopStack.isEmpty()) + return ProItem::ReturnNext; + q->logMessage(format("unexpected next().")); + return ProItem::ReturnFalse; + case T_IF: { + if (args.count() != 1) { + q->logMessage(format("if(condition) requires one argument.")); + return ProItem::ReturnFalse; + } + QString cond = args.first(); + bool escaped = false; // This is more than qmake does + bool quoted = false; + bool ret = true; + bool orOp = false; + bool invert = false; + bool isFunc = false; + int parens = 0; + QString test; + test.reserve(20); + QString args; + args.reserve(50); + const QChar *d = cond.unicode(); + const QChar *ed = d + cond.length(); + while (d < ed) { + ushort c = (d++)->unicode(); + if (!escaped) { + if (c == '\\') { + escaped = true; + args += c; // Assume no-one quotes the test name + continue; + } else if (c == '"') { + quoted = !quoted; + args += c; // Ditto + continue; + } + } else { + escaped = false; + } + if (quoted) { + args += c; // Ditto + } else { + bool isOp = false; + if (c == '(') { + isFunc = true; + if (parens) + args += c; + ++parens; + } else if (c == ')') { + --parens; + if (parens) + args += c; + } else if (!parens) { + if (c == ':' || c == '|') + isOp = true; + else if (c == '!') + invert = true; + else + test += c; + } else { + args += c; + } + if (!parens && (isOp || d == ed)) { + // Yes, qmake doesn't shortcut evaluations here. We can't, either, + // as some test functions have side effects. + bool success; + if (isFunc) { + success = evaluateConditionalFunction(test, args); + } else { + success = isActiveConfig(test, true); + } + success ^= invert; + if (orOp) + ret |= success; + else + ret &= success; + orOp = (c == '|'); + invert = false; + isFunc = false; + test.clear(); + args.clear(); + } + } + } + return returnBool(ret); + } + case T_CONFIG: { if (args.count() < 1 || args.count() > 2) { q->logMessage(format("CONFIG(config) requires one or two arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } if (args.count() == 1) { //cond = isActiveConfig(args.first()); XXX - break; + return ProItem::ReturnFalse; } const QStringList mutuals = args[1].split(QLatin1Char('|')); const QStringList &configs = valuesDirect(QLatin1String("CONFIG")); - for (int i = configs.size() - 1 && ok; i >= 0; i--) { + for (int i = configs.size() - 1; i >= 0; i--) { for (int mut = 0; mut < mutuals.count(); mut++) { if (configs[i] == mutuals[mut].trimmed()) { - cond = (configs[i] == args[0]); - goto done_T_CONFIG; + return returnBool(configs[i] == args[0]); } } } - done_T_CONFIG: - break; + return ProItem::ReturnFalse; } - case CF_CONTAINS: { + case T_CONTAINS: { if (args.count() < 2 || args.count() > 3) { q->logMessage(format("contains(var, val) requires two or three arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } QRegExp regx(args[1]); @@ -1266,8 +2047,7 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &funct for (int i = 0; i < l.size(); ++i) { const QString val = l[i]; if (regx.exactMatch(val) || val == args[1]) { - cond = true; - break; + return ProItem::ReturnTrue; } } } else { @@ -1276,178 +2056,322 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &funct const QString val = l[i]; for (int mut = 0; mut < mutuals.count(); mut++) { if (val == mutuals[mut].trimmed()) { - cond = (regx.exactMatch(val) || val == args[1]); - goto done_T_CONTAINS; + return returnBool(regx.exactMatch(val) || val == args[1]); } } } } - done_T_CONTAINS: - break; + return ProItem::ReturnFalse; } - case CF_COUNT: { + case T_COUNT: { if (args.count() != 2 && args.count() != 3) { - q->logMessage(format("count(var, count) requires two or three arguments.")); - ok = false; - break; + q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments.")); + return ProItem::ReturnFalse; } if (args.count() == 3) { QString comp = args[2]; if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) { - cond = values(args.first()).count() > args[1].toInt(); + return returnBool(values(args.first()).count() > args[1].toInt()); } else if (comp == QLatin1String(">=")) { - cond = values(args.first()).count() >= args[1].toInt(); + return returnBool(values(args.first()).count() >= args[1].toInt()); } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) { - cond = values(args.first()).count() < args[1].toInt(); + return returnBool(values(args.first()).count() < args[1].toInt()); } else if (comp == QLatin1String("<=")) { - cond = values(args.first()).count() <= args[1].toInt(); - } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") || comp == QLatin1String("=") || comp == QLatin1String("==")) { - cond = values(args.first()).count() == args[1].toInt(); + return returnBool(values(args.first()).count() <= args[1].toInt()); + } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") + || comp == QLatin1String("=") || comp == QLatin1String("==")) { + return returnBool(values(args.first()).count() == args[1].toInt()); } else { - ok = false; q->logMessage(format("unexpected modifier to count(%2)").arg(comp)); + return ProItem::ReturnFalse; } - break; } - cond = values(args.first()).count() == args[1].toInt(); - break; + return returnBool(values(args.first()).count() == args[1].toInt()); + } + case T_GREATERTHAN: + case T_LESSTHAN: { + if (args.count() != 2) { + q->logMessage(format("%1(variable, value) requires two arguments.").arg(function)); + return ProItem::ReturnFalse; + } + QString rhs(args[1]), lhs(values(args[0]).join(QString(Option::field_sep))); + bool ok; + int rhs_int = rhs.toInt(&ok); + if (ok) { // do integer compare + int lhs_int = lhs.toInt(&ok); + if (ok) { + if (func_t == T_GREATERTHAN) + return returnBool(lhs_int > rhs_int); + return returnBool(lhs_int < rhs_int); + } + } + if (func_t == T_GREATERTHAN) + return returnBool(lhs > rhs); + return returnBool(lhs < rhs); + } + case T_EQUALS: + if (args.count() != 2) { + q->logMessage(format("%1(variable, value) requires two arguments.").arg(function)); + return ProItem::ReturnFalse; + } + return returnBool(values(args[0]).join(QString(Option::field_sep)) == args[1]); + case T_CLEAR: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; + if (args.count() != 1) { + q->logMessage(format("%1(variable) requires one argument.").arg(function)); + return ProItem::ReturnFalse; + } + QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]); + if (it == m_valuemap.end()) + return ProItem::ReturnFalse; + it->clear(); + return ProItem::ReturnTrue; + } + case T_UNSET: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; + if (args.count() != 1) { + q->logMessage(format("%1(variable) requires one argument.").arg(function)); + return ProItem::ReturnFalse; + } + QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]); + if (it == m_valuemap.end()) + return ProItem::ReturnFalse; + m_valuemap.erase(it); + return ProItem::ReturnTrue; } - case CF_INCLUDE: { + case T_INCLUDE: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; QString parseInto; - if (args.count() == 2) { + // the third optional argument to include() controls warnings + // and is not used here + if ((args.count() == 2) || (args.count() == 3)) { parseInto = args[1]; } else if (args.count() != 1) { - q->logMessage(format("include(file) requires one or two arguments.")); - ok = false; - break; + q->logMessage(format("include(file) requires one, two or three arguments.")); + return ProItem::ReturnFalse; } QString fileName = args.first(); // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style. - QDir currentProPath(getcwd()); + QDir currentProPath(currentDirectory()); fileName = QDir::cleanPath(currentProPath.absoluteFilePath(fileName)); - ok = evaluateFile(fileName, &ok); - break; + State sts = m_sts; + bool ok = evaluateFile(fileName); + m_sts = sts; + return returnBool(ok); } - case CF_LOAD: { + case T_LOAD: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; QString parseInto; bool ignore_error = false; if (args.count() == 2) { QString sarg = args[1]; - ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt()); + ignore_error = (!sarg.compare(QLatin1String("true"), Qt::CaseInsensitive) || sarg.toInt()); } else if (args.count() != 1) { q->logMessage(format("load(feature) requires one or two arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } - ok = evaluateFeatureFile( args.first(), &cond); - break; + // XXX ignore_error unused + return returnBool(evaluateFeatureFile(args.first())); } - case CF_MESSAGE: { + case T_DEBUG: + // Yup - do nothing. Nothing is going to enable debug output anyway. + return ProItem::ReturnFalse; + case T_MESSAGE: { if (args.count() != 1) { q->logMessage(format("%1(message) requires one argument.").arg(function)); - ok = false; - break; + return ProItem::ReturnFalse; } - QString msg = args.first(); - if (function == QLatin1String("error")) { - QStringList parents; - foreach (ProFile *proFile, m_profileStack) - parents.append(proFile->fileName()); - if (!parents.isEmpty()) - parents.takeLast(); - if (parents.isEmpty()) - q->fileMessage(format("Project ERROR: %1").arg(msg)); - else - q->fileMessage(format("Project ERROR: %1. File was included from: '%2'") - .arg(msg).arg(parents.join(QLatin1String("', '")))); - } else { - q->fileMessage(format("Project MESSAGE: %1").arg(msg)); - } - break; + QString msg = fixEnvVariables(args.first()); + q->fileMessage(QString::fromLatin1("Project %1: %2").arg(function.toUpper(), msg)); + // ### Consider real termination in non-cumulative mode + return returnBool(function != QLatin1String("error")); } - case CF_SYSTEM: { +#if 0 // Way too dangerous to enable. + case T_SYSTEM: { if (args.count() != 1) { q->logMessage(format("system(exec) requires one argument.")); - ok = false; - break; + ProItem::ReturnFalse; } - ok = system(args.first().toLatin1().constData()) == 0; - break; + return returnBool(system(args.first().toLatin1().constData()) == 0); } - case CF_ISEMPTY: { +#endif + case T_ISEMPTY: { if (args.count() != 1) { q->logMessage(format("isEmpty(var) requires one argument.")); - ok = false; - break; + return ProItem::ReturnFalse; } QStringList sl = values(args.first()); if (sl.count() == 0) { - cond = true; + return ProItem::ReturnTrue; } else if (sl.count() > 0) { QString var = sl.first(); - cond = (var.isEmpty()); + if (var.isEmpty()) + return ProItem::ReturnTrue; } - break; + return ProItem::ReturnFalse; } - case CF_EXISTS: { + case T_EXISTS: { if (args.count() != 1) { q->logMessage(format("exists(file) requires one argument.")); - ok = false; - break; + return ProItem::ReturnFalse; } QString file = args.first(); - - file = QDir::cleanPath(file); + file = Option::fixPathToLocalOS(file); if (QFile::exists(file)) { - cond = true; - break; + return ProItem::ReturnTrue; } //regular expression I guess - QString dirstr = getcwd(); + QString dirstr = currentDirectory(); int slsh = file.lastIndexOf(Option::dir_sep); if (slsh != -1) { dirstr = file.left(slsh+1); file = file.right(file.length() - slsh - 1); } - cond = QDir(dirstr).entryList(QStringList(file)).count(); + if (file.contains(QLatin1Char('*')) || file.contains(QLatin1Char('?'))) + if (!QDir(dirstr).entryList(QStringList(file)).isEmpty()) + return ProItem::ReturnTrue; - break; + return ProItem::ReturnFalse; } + case 0: + q->logMessage(format("'%1' is not a recognized test function").arg(function)); + return ProItem::ReturnFalse; + default: + q->logMessage(format("Function '%1' is not implemented").arg(function)); + return ProItem::ReturnFalse; } +} - if (result) - *result = cond; +QStringList ProFileEvaluator::Private::values(const QString &variableName, + const QHash<QString, QStringList> &place, + const ProFile *pro) const +{ + if (variableName == QLatin1String("LITERAL_WHITESPACE")) //a real space in a token + return QStringList(QLatin1String("\t")); + if (variableName == QLatin1String("LITERAL_DOLLAR")) //a real $ + return QStringList(QLatin1String("$")); + if (variableName == QLatin1String("LITERAL_HASH")) //a real # + return QStringList(QLatin1String("#")); + if (variableName == QLatin1String("OUT_PWD")) //the out going dir + return QStringList(m_outputDir); + if (variableName == QLatin1String("PWD") || //current working dir (of _FILE_) + variableName == QLatin1String("IN_PWD")) + return QStringList(currentDirectory()); + if (variableName == QLatin1String("DIR_SEPARATOR")) + return QStringList(Option::dir_sep); + if (variableName == QLatin1String("DIRLIST_SEPARATOR")) + return QStringList(Option::dirlist_sep); + if (variableName == QLatin1String("_LINE_")) //parser line number + return QStringList(QString::number(m_lineNo)); + if (variableName == QLatin1String("_FILE_")) //parser file; qmake is a bit weird here + return QStringList(m_profileStack.size() == 1 ? pro->fileName() : QFileInfo(pro->fileName()).fileName()); + if (variableName == QLatin1String("_DATE_")) //current date/time + return QStringList(QDateTime::currentDateTime().toString()); + if (variableName == QLatin1String("_PRO_FILE_")) + return QStringList(m_origfile); + if (variableName == QLatin1String("_PRO_FILE_PWD_")) + return QStringList(QFileInfo(m_origfile).absolutePath()); + if (variableName == QLatin1String("_QMAKE_CACHE_")) + return QStringList(); // FIXME? + if (variableName.startsWith(QLatin1String("QMAKE_HOST."))) { + QString ret, type = variableName.mid(11); +#if defined(Q_OS_WIN32) + if (type == QLatin1String("os")) { + ret = QLatin1String("Windows"); + } else if (type == QLatin1String("name")) { + DWORD name_length = 1024; + wchar_t name[1024]; + if (GetComputerName(name, &name_length)) + ret = QString::fromWCharArray(name); + } else if (type == QLatin1String("version") || type == QLatin1String("version_string")) { + QSysInfo::WinVersion ver = QSysInfo::WindowsVersion; + if (type == QLatin1String("version")) + ret = QString::number(ver); + else if (ver == QSysInfo::WV_Me) + ret = QLatin1String("WinMe"); + else if (ver == QSysInfo::WV_95) + ret = QLatin1String("Win95"); + else if (ver == QSysInfo::WV_98) + ret = QLatin1String("Win98"); + else if (ver == QSysInfo::WV_NT) + ret = QLatin1String("WinNT"); + else if (ver == QSysInfo::WV_2000) + ret = QLatin1String("Win2000"); + else if (ver == QSysInfo::WV_2000) + ret = QLatin1String("Win2003"); + else if (ver == QSysInfo::WV_XP) + ret = QLatin1String("WinXP"); + else if (ver == QSysInfo::WV_VISTA) + ret = QLatin1String("WinVista"); + else + ret = QLatin1String("Unknown"); + } else if (type == QLatin1String("arch")) { + SYSTEM_INFO info; + GetSystemInfo(&info); + switch(info.wProcessorArchitecture) { +#ifdef PROCESSOR_ARCHITECTURE_AMD64 + case PROCESSOR_ARCHITECTURE_AMD64: + ret = QLatin1String("x86_64"); + break; +#endif + case PROCESSOR_ARCHITECTURE_INTEL: + ret = QLatin1String("x86"); + break; + case PROCESSOR_ARCHITECTURE_IA64: +#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: +#endif + ret = QLatin1String("IA64"); + break; + default: + ret = QLatin1String("Unknown"); + break; + } + } +#elif defined(Q_OS_UNIX) + struct utsname name; + if (!uname(&name)) { + if (type == QLatin1String("os")) + ret = QString::fromLatin1(name.sysname); + else if (type == QLatin1String("name")) + ret = QString::fromLatin1(name.nodename); + else if (type == QLatin1String("version")) + ret = QString::fromLatin1(name.release); + else if (type == QLatin1String("version_string")) + ret = QString::fromLatin1(name.version); + else if (type == QLatin1String("arch")) + ret = QString::fromLatin1(name.machine); + } +#endif + return QStringList(ret); + } - return ok; + QStringList result = place[variableName]; + if (result.isEmpty()) { + if (variableName == QLatin1String("TARGET")) { + result.append(QFileInfo(m_origfile).baseName()); + } else if (variableName == QLatin1String("TEMPLATE")) { + result.append(QLatin1String("app")); + } else if (variableName == QLatin1String("QMAKE_DIR_SEP")) { + result.append(Option::dirlist_sep); + } + } + return result; } QStringList ProFileEvaluator::Private::values(const QString &variableName) const { - if (variableName == QLatin1String("TARGET")) { - QStringList list = m_valuemap.value(variableName); - if (!m_origfile.isEmpty()) - list.append(QFileInfo(m_origfile).baseName()); - return list; - } - if (variableName == QLatin1String("PWD")) { - return QStringList(getcwd()); - } - return m_valuemap.value(variableName); + return values(variableName, m_valuemap, currentProFile()); } QStringList ProFileEvaluator::Private::values(const QString &variableName, const ProFile *pro) const { - if (variableName == QLatin1String("TARGET")) { - QStringList list = m_filevaluemap[pro].value(variableName); - if (!m_origfile.isEmpty()) - list.append(QFileInfo(m_origfile).baseName()); - return list; - } - if (variableName == QLatin1String("PWD")) { - return QStringList(QFileInfo(pro->fileName()).absoluteFilePath()); - } - return m_filevaluemap[pro].value(variableName); + return values(variableName, m_filevaluemap[pro], pro); } ProFile *ProFileEvaluator::parsedProFile(const QString &fileName) @@ -1473,27 +2397,21 @@ void ProFileEvaluator::releaseParsedProFile(ProFile *proFile) delete proFile; } -bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *result) +bool ProFileEvaluator::Private::evaluateFile(const QString &fileName) { - bool ok = true; ProFile *pro = q->parsedProFile(fileName); if (pro) { m_profileStack.push(pro); - ok = pro->Accept(this); + bool ok = (pro->Accept(this) == ProItem::ReturnTrue); m_profileStack.pop(); q->releaseParsedProFile(pro); - - if (result) - *result = true; + return ok; } else { - if (result) - *result = false; + return false; } - - return ok; } -bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, bool *result) +bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName) { QString fn; foreach (const QString &path, qmakeFeaturePaths()) { @@ -1508,7 +2426,13 @@ bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, boo break; } } - return fn.isEmpty() ? false : evaluateFile(fn, result); + if (fn.isEmpty()) + return false; + bool cumulative = m_cumulative; + m_cumulative = false; + bool ok = evaluateFile(fn); + m_cumulative = cumulative; + return ok; } QString ProFileEvaluator::Private::format(const char *fmt) const @@ -1542,14 +2466,23 @@ bool ProFileEvaluator::contains(const QString &variableName) const return d->m_valuemap.contains(variableName); } +inline QStringList fixEnvVariables(const QStringList &x) +{ + QStringList ret; + foreach (const QString &str, x) + ret << Option::fixString(str, Option::FixEnvVars); + return ret; +} + + QStringList ProFileEvaluator::values(const QString &variableName) const { - return d->values(variableName); + return fixEnvVariables(d->values(variableName)); } QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const { - return d->values(variableName, pro); + return fixEnvVariables(d->values(variableName, pro)); } QStringList ProFileEvaluator::absolutePathValues( @@ -1609,12 +2542,14 @@ ProFileEvaluator::TemplateType ProFileEvaluator::templateType() { QStringList templ = values(QLatin1String("TEMPLATE")); if (templ.count() >= 1) { - QString t = templ.last().toLower(); - if (t == QLatin1String("app")) + const QString &t = templ.last(); + if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive)) return TT_Application; - if (t == QLatin1String("lib")) + if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive)) return TT_Library; - if (t == QLatin1String("subdirs")) + if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive)) + return TT_Script; + if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive)) return TT_Subdirs; } return TT_Unknown; @@ -1658,18 +2593,20 @@ void ProFileEvaluator::addProperties(const QHash<QString, QString> &properties) void ProFileEvaluator::logMessage(const QString &message) { - if (d->m_verbose) + if (d->m_verbose && !d->m_skipLevel) qWarning("%s", qPrintable(message)); } void ProFileEvaluator::fileMessage(const QString &message) { - qWarning("%s", qPrintable(message)); + if (!d->m_skipLevel) + qWarning("%s", qPrintable(message)); } void ProFileEvaluator::errorMessage(const QString &message) { - qWarning("%s", qPrintable(message)); + if (!d->m_skipLevel) + qWarning("%s", qPrintable(message)); } void ProFileEvaluator::setVerbose(bool on) @@ -1677,4 +2614,14 @@ void ProFileEvaluator::setVerbose(bool on) d->m_verbose = on; } +void ProFileEvaluator::setCumulative(bool on) +{ + d->m_cumulative = on; +} + +void ProFileEvaluator::setOutputDir(const QString &dir) +{ + d->m_outputDir = dir; +} + QT_END_NAMESPACE diff --git a/tools/linguist/shared/profileevaluator.h b/tools/linguist/shared/profileevaluator.h index 43a9ce4..7f947e0 100644 --- a/tools/linguist/shared/profileevaluator.h +++ b/tools/linguist/shared/profileevaluator.h @@ -50,15 +50,27 @@ #include <QtCore/QStringList> #include <QtCore/QStack> +#if (!defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) && !defined(__SUNPRO_CC) +# define HAVE_TEMPLATE_CLASS_FRIENDS +#endif + QT_BEGIN_NAMESPACE class ProFileEvaluator { +#ifdef HAVE_TEMPLATE_CLASS_FRIENDS +private: +#else +public: +#endif + class Private; + public: enum TemplateType { TT_Unknown = 0, TT_Application, TT_Library, + TT_Script, TT_Subdirs }; @@ -67,7 +79,9 @@ public: ProFileEvaluator::TemplateType templateType(); virtual bool contains(const QString &variableName) const; - void setVerbose(bool on); + void setVerbose(bool on); // Default is false + void setCumulative(bool on); // Default is true! + void setOutputDir(const QString &dir); // Default is empty bool queryProFile(ProFile *pro); bool accept(ProFile *pro); @@ -90,8 +104,11 @@ public: virtual void fileMessage(const QString &msg); // error() and message() from .pro file private: - class Private; Private *d; + +#ifdef HAVE_TEMPLATE_CLASS_FRIENDS + template<typename T> friend class QTypeInfo; +#endif }; QT_END_NAMESPACE diff --git a/tools/linguist/shared/proitems.cpp b/tools/linguist/shared/proitems.cpp index 83a31bb..e1563d5 100644 --- a/tools/linguist/shared/proitems.cpp +++ b/tools/linguist/shared/proitems.cpp @@ -58,15 +58,21 @@ QString ProItem::comment() const } // --------------- ProBlock ---------------- + ProBlock::ProBlock(ProBlock *parent) { m_blockKind = 0; m_parent = parent; + m_refCount = 1; } ProBlock::~ProBlock() { - qDeleteAll(m_proitems); + foreach (ProItem *itm, m_proitems) + if (itm->kind() == BlockKind) + static_cast<ProBlock *>(itm)->deref(); + else + delete itm; } void ProBlock::appendItem(ProItem *proitem) @@ -109,14 +115,37 @@ ProItem::ProItemKind ProBlock::kind() const return ProItem::BlockKind; } -bool ProBlock::Accept(AbstractProItemVisitor *visitor) -{ - visitor->visitBeginProBlock(this); - foreach (ProItem *item, m_proitems) { - if (!item->Accept(visitor)) - return false; +ProItem::ProItemReturn ProBlock::Accept(AbstractProItemVisitor *visitor) +{ + if (visitor->visitBeginProBlock(this) == ReturnSkip) + return ReturnTrue; + ProItemReturn rt = ReturnTrue; + for (int i = 0; i < m_proitems.count(); ++i) { + rt = m_proitems.at(i)->Accept(visitor); + if (rt != ReturnTrue && rt != ReturnFalse) { + if (rt == ReturnLoop) { + rt = ReturnTrue; + while (visitor->visitProLoopIteration()) + for (int j = i; ++j < m_proitems.count(); ) { + rt = m_proitems.at(j)->Accept(visitor); + if (rt != ReturnTrue && rt != ReturnFalse) { + if (rt == ReturnNext) { + rt = ReturnTrue; + break; + } + if (rt == ReturnBreak) + rt = ReturnTrue; + goto do_break; + } + } + do_break: + visitor->visitProLoopCleanup(); + } + break; + } } - return visitor->visitEndProBlock(this); + visitor->visitEndProBlock(this); + return rt; } // --------------- ProVariable ---------------- @@ -148,14 +177,13 @@ QString ProVariable::variable() const return m_variable; } -bool ProVariable::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProVariable::Accept(AbstractProItemVisitor *visitor) { visitor->visitBeginProVariable(this); - foreach (ProItem *item, m_proitems) { - if (!item->Accept(visitor)) - return false; - } - return visitor->visitEndProVariable(this); + foreach (ProItem *item, m_proitems) + item->Accept(visitor); // cannot fail + visitor->visitEndProVariable(this); + return ReturnTrue; } // --------------- ProValue ---------------- @@ -190,9 +218,10 @@ ProItem::ProItemKind ProValue::kind() const return ProItem::ValueKind; } -bool ProValue::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProValue::Accept(AbstractProItemVisitor *visitor) { - return visitor->visitProValue(this); + visitor->visitProValue(this); + return ReturnTrue; } // --------------- ProFunction ---------------- @@ -216,7 +245,7 @@ ProItem::ProItemKind ProFunction::kind() const return ProItem::FunctionKind; } -bool ProFunction::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProFunction::Accept(AbstractProItemVisitor *visitor) { return visitor->visitProFunction(this); } @@ -242,9 +271,10 @@ ProItem::ProItemKind ProCondition::kind() const return ProItem::ConditionKind; } -bool ProCondition::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProCondition::Accept(AbstractProItemVisitor *visitor) { - return visitor->visitProCondition(this); + visitor->visitProCondition(this); + return ReturnTrue; } // --------------- ProOperator ---------------- @@ -268,9 +298,10 @@ ProItem::ProItemKind ProOperator::kind() const return ProItem::OperatorKind; } -bool ProOperator::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProOperator::Accept(AbstractProItemVisitor *visitor) { - return visitor->visitProOperator(this); + visitor->visitProOperator(this); + return ReturnTrue; } // --------------- ProFile ---------------- @@ -315,13 +346,12 @@ bool ProFile::isModified() const return m_modified; } -bool ProFile::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProFile::Accept(AbstractProItemVisitor *visitor) { - visitor->visitBeginProFile(this); - foreach (ProItem *item, m_proitems) { - if (!item->Accept(visitor)) - return false; - } + ProItemReturn rt; + if ((rt = visitor->visitBeginProFile(this)) != ReturnTrue) + return rt; + ProBlock::Accept(visitor); // cannot fail return visitor->visitEndProFile(this); } diff --git a/tools/linguist/shared/proitems.h b/tools/linguist/shared/proitems.h index 5e36629..7ad1bb8 100644 --- a/tools/linguist/shared/proitems.h +++ b/tools/linguist/shared/proitems.h @@ -60,6 +60,16 @@ public: BlockKind }; + enum ProItemReturn { + ReturnFalse, + ReturnTrue, + ReturnBreak, + ReturnNext, + ReturnLoop, + ReturnSkip, + ReturnReturn + }; + ProItem() : m_lineNumber(0) {} virtual ~ProItem() {} @@ -68,7 +78,7 @@ public: void setComment(const QString &comment); QString comment() const; - virtual bool Accept(AbstractProItemVisitor *visitor) = 0; + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor) = 0; int lineNumber() const { return m_lineNumber; } void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; } @@ -86,7 +96,8 @@ public: ScopeContentsKind = 0x02, VariableKind = 0x04, ProFileKind = 0x08, - SingleLine = 0x10 + FunctionBodyKind = 0x10, + SingleLine = 0x80 }; ProBlock(ProBlock *parent); @@ -102,14 +113,18 @@ public: void setParent(ProBlock *parent); ProBlock *parent() const; + void ref() { ++m_refCount; } + void deref() { if (!--m_refCount) delete this; } + ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); protected: QList<ProItem *> m_proitems; private: ProBlock *m_parent; int m_blockKind; + int m_refCount; }; class ProVariable : public ProBlock @@ -131,7 +146,7 @@ public: void setVariable(const QString &name); QString variable() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: VariableOperator m_variableKind; QString m_variable; @@ -150,7 +165,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_value; ProVariable *m_variable; @@ -166,7 +181,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_text; }; @@ -181,7 +196,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_text; }; @@ -201,7 +216,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: OperatorKind m_operatorKind; }; @@ -219,7 +234,7 @@ public: void setModified(bool modified); bool isModified() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_fileName; diff --git a/tools/linguist/shared/proparserutils.h b/tools/linguist/shared/proparserutils.h index 6e19236..8dd8c6d 100644 --- a/tools/linguist/shared/proparserutils.h +++ b/tools/linguist/shared/proparserutils.h @@ -93,6 +93,25 @@ struct Option Option::qmakespec = QString::fromLatin1(qgetenv("QMAKESPEC").data()); Option::field_sep = QLatin1Char(' '); } + + enum StringFixFlags { + FixNone = 0x00, + FixEnvVars = 0x01, + FixPathCanonicalize = 0x02, + FixPathToLocalSeparators = 0x04, + FixPathToTargetSeparators = 0x08 + }; + static QString fixString(QString string, uchar flags); + + inline static QString fixPathToLocalOS(const QString &in, bool fix_env = true, bool canonical = true) + { + uchar flags = FixPathToLocalSeparators; + if (fix_env) + flags |= FixEnvVars; + if (canonical) + flags |= FixPathCanonicalize; + return fixString(in, flags); + } }; #if defined(Q_OS_WIN32) Option::TARG_MODE Option::target_mode = Option::TARG_WIN_MODE; @@ -110,17 +129,20 @@ QString Option::dir_sep; QChar Option::field_sep; static void insertUnique(QHash<QString, QStringList> *map, - const QString &key, const QStringList &value, bool unique = true) + const QString &key, const QStringList &value) { QStringList &sl = (*map)[key]; - if (!unique) { - sl += value; - } else { - for (int i = 0; i < value.count(); ++i) { - if (!sl.contains(value.at(i))) - sl.append(value.at(i)); - } - } + foreach (const QString &str, value) + if (!sl.contains(str)) + sl.append(str); +} + +static void removeEach(QHash<QString, QStringList> *map, + const QString &key, const QStringList &value) +{ + QStringList &sl = (*map)[key]; + foreach (const QString &str, value) + sl.removeAll(str); } /* @@ -148,7 +170,12 @@ static QStringList replaceInList(const QStringList &varList, const QRegExp ®e } */ -inline QStringList splitPathList(const QString paths) +inline QString fixEnvVariables(const QString &x) +{ + return Option::fixString(x, Option::FixEnvVars); +} + +inline QStringList splitPathList(const QString &paths) { return paths.split(Option::dirlist_sep); } @@ -255,7 +282,7 @@ static QStringList split_value_list(const QString &vals, bool do_semicolon=false static QStringList qmake_mkspec_paths() { QStringList ret; - const QString concat = QDir::separator() + QString(QLatin1String("mkspecs")); + const QString concat = QDir::separator() + QLatin1String("mkspecs"); QByteArray qmakepath = qgetenv("QMAKEPATH"); if (!qmakepath.isEmpty()) { const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath)); diff --git a/tools/linguist/shared/qm.cpp b/tools/linguist/shared/qm.cpp index 55d1504..489279f 100644 --- a/tools/linguist/shared/qm.cpp +++ b/tools/linguist/shared/qm.cpp @@ -173,6 +173,7 @@ public: bool save(QIODevice *iod); void insert(const TranslatorMessage &msg, bool forceComment); + void insertIdBased(const TranslatorMessage &message); void squeeze(TranslatorSaveMode mode); @@ -238,17 +239,13 @@ Prefix Releaser::commonPrefix(const ByteTranslatorMessage &m1, const ByteTransla void Releaser::writeMessage(const ByteTranslatorMessage &msg, QDataStream &stream, TranslatorSaveMode mode, Prefix prefix) const { - for (int i = 0; i < msg.translations().count(); ++i) { - QString str = msg.translations().at(i); - str.replace(QChar(Translator::DefaultVariantSeparator), - QChar(Translator::InternalVariantSeparator)); - stream << quint8(Tag_Translation) << str; - } + for (int i = 0; i < msg.translations().count(); ++i) + stream << quint8(Tag_Translation) << msg.translations().at(i); if (mode == SaveEverything) prefix = HashContextSourceTextComment; - // lrelease produces "wrong" .qm files for QByteArrays that are .isNull(). + // lrelease produces "wrong" QM files for QByteArrays that are .isNull(). switch (prefix) { default: case HashContextSourceTextComment: @@ -440,6 +437,16 @@ void Releaser::insert(const TranslatorMessage &message, bool forceComment) insertInternal(message, forceComment, false); } +void Releaser::insertIdBased(const TranslatorMessage &message) +{ + QStringList tlns = message.translations(); + for (int i = 0; i < tlns.size(); ++i) + if (tlns.at(i).isEmpty()) + tlns[i] = message.sourceText(); + ByteTranslatorMessage bmsg("", originalBytes(message.id(), false), "", tlns); + m_messages.insert(bmsg, 0); +} + void Releaser::setNumerusRules(const QByteArray &rules) { m_numerusRules = rules; @@ -593,8 +600,6 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) str[i] = QChar((str.at(i).unicode() >> 8) + ((str.at(i).unicode() << 8) & 0xff00)); } - str.replace(QChar(Translator::InternalVariantSeparator), - QChar(Translator::DefaultVariantSeparator)); translations << str; m += len; break; @@ -696,11 +701,17 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData int finished = 0; int unfinished = 0; int untranslated = 0; + int missingIds = 0; + int droppedData = 0; for (int i = 0; i != translator.messageCount(); ++i) { const TranslatorMessage &msg = translator.message(i); TranslatorMessage::Type typ = msg.type(); if (typ != TranslatorMessage::Obsolete) { + if (cd.m_idBased && msg.id().isEmpty()) { + ++missingIds; + continue; + } if (typ == TranslatorMessage::Unfinished) { if (msg.translation().isEmpty()) { ++untranslated; @@ -713,19 +724,34 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData } else { ++finished; } - // Drop the comment in (context, sourceText, comment), - // unless the context is empty, - // unless (context, sourceText, "") already exists or - // unless we already dropped the comment of (context, - // sourceText, comment0). - bool forceComment = - msg.comment().isEmpty() - || msg.context().isEmpty() - || translator.contains(msg.context(), msg.sourceText(), QString()); - releaser.insert(msg, forceComment); + if (cd.m_idBased) { + if (!msg.context().isEmpty() || !msg.comment().isEmpty()) + ++droppedData; + releaser.insertIdBased(msg); + } else { + // Drop the comment in (context, sourceText, comment), + // unless the context is empty, + // unless (context, sourceText, "") already exists or + // unless we already dropped the comment of (context, + // sourceText, comment0). + bool forceComment = + msg.comment().isEmpty() + || msg.context().isEmpty() + || translator.contains(msg.context(), msg.sourceText(), QString()); + releaser.insert(msg, forceComment); + } } } + if (missingIds) + cd.appendError(QCoreApplication::translate("LRelease", + "Dropped %n message(s) which had no ID.", 0, + QCoreApplication::CodecForTr, missingIds)); + if (droppedData) + cd.appendError(QCoreApplication::translate("LRelease", + "Excess context/disambiguation dropped from %n message(s).", 0, + QCoreApplication::CodecForTr, droppedData)); + releaser.squeeze(cd.m_saveMode); bool saved = releaser.save(&dev); if (saved && cd.isVerbose()) { diff --git a/tools/linguist/shared/qph.cpp b/tools/linguist/shared/qph.cpp index dcc48eb..78a8cbb 100644 --- a/tools/linguist/shared/qph.cpp +++ b/tools/linguist/shared/qph.cpp @@ -54,33 +54,19 @@ QT_BEGIN_NAMESPACE class QPHReader : public QXmlStreamReader { public: - QPHReader(QIODevice &dev, ConversionData &cd) - : QXmlStreamReader(&dev), m_cd(cd) + QPHReader(QIODevice &dev) + : QXmlStreamReader(&dev) {} // the "real thing" bool read(Translator &translator); private: - bool elementStarts(const QString &str) const - { - return isStartElement() && name() == str; - } - bool isWhiteSpace() const { return isCharacters() && text().toString().trimmed().isEmpty(); } - // needed to expand <byte ... /> - QString readContents(); - // needed to join <lengthvariant>s - QString readTransContents(); - - void handleError(); - - ConversionData &m_cd; - enum DataField { NoField, SourceField, TargetField, DefinitionField }; DataField m_currentField; QString m_currentSource; @@ -113,6 +99,8 @@ bool QPHReader::read(Translator &translator) else if (m_currentField == DefinitionField) m_currentDefinition += text(); } else if (isEndElement() && name() == QLatin1String("phrase")) { + m_currentTarget.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); TranslatorMessage msg; msg.setSourceText(m_currentSource); msg.setTranslation(m_currentTarget); @@ -126,10 +114,10 @@ bool QPHReader::read(Translator &translator) return true; } -static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &cd) +static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &) { translator.setLocationsType(Translator::NoLocations); - QPHReader reader(dev, cd); + QPHReader reader(dev); return reader.read(translator); } @@ -173,7 +161,10 @@ static bool saveQPH(const Translator &translator, QIODevice &dev, ConversionData foreach (const TranslatorMessage &msg, translator.messages()) { t << "<phrase>\n"; t << " <source>" << protect(msg.sourceText()) << "</source>\n"; - t << " <target>" << protect(msg.translations().join(QLatin1String("@"))) + QString str = msg.translations().join(QLatin1String("@")); + str.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); + t << " <target>" << protect(str) << "</target>\n"; if (!msg.context().isEmpty() || !msg.comment().isEmpty()) t << " <definition>" << msg.context() << msg.comment() diff --git a/tools/linguist/shared/qscript.cpp b/tools/linguist/shared/qscript.cpp deleted file mode 100644 index 12491bf..0000000 --- a/tools/linguist/shared/qscript.cpp +++ /dev/null @@ -1,2408 +0,0 @@ -// This file was generated by qlalr - DO NOT EDIT! -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -class QScriptGrammar -{ -public: - enum { - EOF_SYMBOL = 0, - T_AND = 1, - T_AND_AND = 2, - T_AND_EQ = 3, - T_AUTOMATIC_SEMICOLON = 62, - T_BREAK = 4, - T_CASE = 5, - T_CATCH = 6, - T_COLON = 7, - T_COMMA = 8, - T_CONST = 81, - T_CONTINUE = 9, - T_DEBUGGER = 82, - T_DEFAULT = 10, - T_DELETE = 11, - T_DIVIDE_ = 12, - T_DIVIDE_EQ = 13, - T_DO = 14, - T_DOT = 15, - T_ELSE = 16, - T_EQ = 17, - T_EQ_EQ = 18, - T_EQ_EQ_EQ = 19, - T_FALSE = 80, - T_FINALLY = 20, - T_FOR = 21, - T_FUNCTION = 22, - T_GE = 23, - T_GT = 24, - T_GT_GT = 25, - T_GT_GT_EQ = 26, - T_GT_GT_GT = 27, - T_GT_GT_GT_EQ = 28, - T_IDENTIFIER = 29, - T_IF = 30, - T_IN = 31, - T_INSTANCEOF = 32, - T_LBRACE = 33, - T_LBRACKET = 34, - T_LE = 35, - T_LPAREN = 36, - T_LT = 37, - T_LT_LT = 38, - T_LT_LT_EQ = 39, - T_MINUS = 40, - T_MINUS_EQ = 41, - T_MINUS_MINUS = 42, - T_NEW = 43, - T_NOT = 44, - T_NOT_EQ = 45, - T_NOT_EQ_EQ = 46, - T_NULL = 78, - T_NUMERIC_LITERAL = 47, - T_OR = 48, - T_OR_EQ = 49, - T_OR_OR = 50, - T_PLUS = 51, - T_PLUS_EQ = 52, - T_PLUS_PLUS = 53, - T_QUESTION = 54, - T_RBRACE = 55, - T_RBRACKET = 56, - T_REMAINDER = 57, - T_REMAINDER_EQ = 58, - T_RESERVED_WORD = 83, - T_RETURN = 59, - T_RPAREN = 60, - T_SEMICOLON = 61, - T_STAR = 63, - T_STAR_EQ = 64, - T_STRING_LITERAL = 65, - T_SWITCH = 66, - T_THIS = 67, - T_THROW = 68, - T_TILDE = 69, - T_TRUE = 79, - T_TRY = 70, - T_TYPEOF = 71, - T_VAR = 72, - T_VOID = 73, - T_WHILE = 74, - T_WITH = 75, - T_XOR = 76, - T_XOR_EQ = 77, - - ACCEPT_STATE = 236, - RULE_COUNT = 267, - STATE_COUNT = 465, - TERMINAL_COUNT = 84, - NON_TERMINAL_COUNT = 88, - - GOTO_INDEX_OFFSET = 465, - GOTO_INFO_OFFSET = 1374, - GOTO_CHECK_OFFSET = 1374 - }; - - static const char *const spell []; - static const int lhs []; - static const int rhs []; - static const int goto_default []; - static const int action_default []; - static const int action_index []; - static const int action_info []; - static const int action_check []; - - static inline int nt_action (int state, int nt) - { - const int *const goto_index = &action_index [GOTO_INDEX_OFFSET]; - const int *const goto_check = &action_check [GOTO_CHECK_OFFSET]; - - const int yyn = goto_index [state] + nt; - - if (yyn < 0 || goto_check [yyn] != nt) - return goto_default [nt]; - - const int *const goto_info = &action_info [GOTO_INFO_OFFSET]; - return goto_info [yyn]; - } - - static inline int t_action (int state, int token) - { - const int yyn = action_index [state] + token; - - if (yyn < 0 || action_check [yyn] != token) - return - action_default [state]; - - return action_info [yyn]; - } -}; - - -const char *const QScriptGrammar::spell [] = { - "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ";", "continue", - "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===", - "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier", - "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=", - "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=", - "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return", - ")", ";", 0, "*", "*=", "string literal", "switch", "this", "throw", "~", - "try", "typeof", "var", "void", "while", "with", "^", "^=", "null", "true", - "false", "const", "debugger", "reserved word"}; - -const int QScriptGrammar::lhs [] = { - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 87, 87, 91, 91, 86, 86, - 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 95, 95, 96, - 96, 96, 96, 96, 99, 99, 100, 100, 100, 100, - 98, 98, 101, 101, 102, 102, 103, 103, 103, 104, - 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, - 105, 105, 105, 106, 106, 106, 107, 107, 107, 107, - 108, 108, 108, 108, 108, 108, 108, 109, 109, 109, - 109, 109, 109, 110, 110, 110, 110, 110, 111, 111, - 111, 111, 111, 112, 112, 113, 113, 114, 114, 115, - 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 123, 123, 90, 90, 124, - 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 89, 89, 126, 126, 127, 127, 128, - 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 130, 146, 146, 145, - 145, 131, 131, 147, 147, 148, 148, 150, 150, 149, - 151, 154, 152, 152, 155, 153, 153, 132, 133, 133, - 134, 134, 135, 135, 135, 135, 135, 135, 135, 136, - 136, 136, 136, 137, 137, 137, 137, 138, 138, 139, - 141, 156, 156, 159, 159, 157, 157, 160, 158, 140, - 142, 142, 143, 143, 143, 161, 162, 144, 163, 97, - 167, 167, 164, 164, 165, 165, 168, 84, 169, 169, - 170, 170, 166, 166, 88, 88, 171}; - -const int QScriptGrammar:: rhs[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, - 3, 5, 3, 3, 2, 4, 1, 2, 0, 1, - 3, 5, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 3, 3, 1, 2, 2, 2, 4, 3, - 2, 3, 1, 3, 1, 1, 1, 2, 2, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, - 3, 3, 3, 1, 3, 3, 1, 3, 3, 3, - 1, 3, 3, 3, 3, 3, 3, 1, 3, 3, - 3, 3, 3, 1, 3, 3, 3, 3, 1, 3, - 3, 3, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 3, 1, 5, 1, 5, 1, 3, 1, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 0, 1, 1, 3, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 1, 2, 0, - 1, 3, 3, 1, 1, 1, 3, 1, 3, 2, - 2, 2, 0, 1, 2, 0, 1, 1, 2, 2, - 7, 5, 7, 7, 5, 9, 10, 7, 8, 2, - 2, 3, 3, 2, 2, 3, 3, 3, 3, 5, - 5, 3, 5, 1, 2, 0, 1, 4, 3, 3, - 3, 3, 3, 3, 4, 5, 2, 1, 8, 8, - 1, 3, 0, 1, 0, 1, 1, 1, 1, 2, - 1, 1, 0, 1, 0, 1, 2}; - -const int QScriptGrammar::action_default [] = { - 0, 97, 164, 128, 136, 132, 172, 179, 76, 148, - 178, 186, 174, 124, 0, 175, 262, 61, 176, 177, - 182, 77, 140, 144, 65, 94, 75, 80, 60, 0, - 114, 180, 101, 259, 258, 261, 183, 0, 194, 0, - 248, 0, 8, 9, 0, 5, 0, 263, 2, 0, - 265, 19, 0, 0, 0, 0, 0, 3, 6, 0, - 0, 166, 208, 7, 0, 1, 0, 0, 4, 0, - 0, 195, 0, 0, 0, 184, 185, 90, 0, 173, - 181, 0, 0, 77, 96, 263, 2, 265, 79, 78, - 0, 0, 0, 92, 93, 91, 0, 264, 253, 254, - 0, 251, 0, 252, 0, 255, 256, 0, 257, 250, - 260, 0, 266, 0, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 23, - 41, 42, 43, 44, 45, 25, 46, 47, 24, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, - 21, 0, 0, 0, 22, 13, 95, 0, 125, 0, - 0, 0, 0, 115, 0, 0, 0, 0, 0, 0, - 105, 0, 0, 0, 99, 100, 98, 103, 107, 106, - 104, 102, 117, 116, 118, 0, 133, 0, 129, 68, - 0, 0, 0, 70, 59, 58, 0, 0, 69, 165, - 0, 73, 71, 0, 72, 74, 209, 210, 0, 161, - 154, 152, 159, 160, 158, 157, 163, 156, 155, 153, - 162, 149, 0, 137, 0, 0, 141, 0, 0, 145, - 67, 0, 0, 63, 0, 62, 267, 224, 0, 225, - 226, 227, 220, 0, 221, 222, 223, 81, 0, 0, - 0, 0, 0, 213, 214, 170, 168, 130, 138, 134, - 150, 126, 171, 0, 77, 142, 146, 119, 108, 0, - 0, 127, 0, 0, 0, 0, 120, 0, 0, 0, - 0, 0, 112, 110, 113, 111, 109, 122, 121, 123, - 0, 135, 0, 131, 0, 169, 77, 0, 151, 166, - 167, 0, 166, 0, 0, 216, 0, 0, 0, 218, - 0, 139, 0, 0, 143, 0, 0, 147, 206, 0, - 198, 207, 201, 0, 205, 0, 166, 199, 0, 166, - 0, 0, 217, 0, 0, 0, 219, 264, 253, 0, - 0, 255, 0, 249, 0, 240, 0, 0, 0, 212, - 0, 211, 188, 191, 0, 27, 30, 31, 248, 34, - 35, 5, 39, 40, 2, 41, 44, 3, 6, 166, - 7, 48, 1, 50, 4, 52, 53, 54, 55, 56, - 57, 189, 187, 65, 66, 64, 0, 228, 229, 0, - 0, 0, 231, 236, 234, 237, 0, 0, 235, 236, - 0, 232, 0, 233, 190, 239, 0, 190, 238, 0, - 241, 242, 0, 190, 243, 244, 0, 0, 245, 0, - 0, 0, 246, 247, 83, 82, 0, 0, 0, 215, - 0, 0, 0, 230, 0, 20, 0, 17, 19, 11, - 0, 16, 12, 18, 15, 10, 0, 14, 87, 85, - 89, 86, 84, 88, 203, 196, 0, 204, 200, 0, - 202, 192, 0, 193, 197}; - -const int QScriptGrammar::goto_default [] = { - 29, 28, 436, 434, 113, 14, 2, 435, 112, 111, - 114, 193, 24, 17, 189, 26, 8, 200, 21, 27, - 77, 25, 1, 32, 30, 267, 13, 261, 3, 257, - 5, 259, 4, 258, 22, 265, 23, 266, 9, 260, - 256, 297, 386, 262, 263, 35, 6, 79, 12, 15, - 18, 19, 10, 7, 31, 80, 20, 36, 75, 76, - 11, 354, 353, 78, 456, 455, 319, 320, 458, 322, - 457, 321, 392, 396, 399, 395, 394, 414, 415, 16, - 100, 107, 96, 99, 106, 108, 33, 0}; - -const int QScriptGrammar::action_index [] = { - 1210, 59, -84, 71, 41, -1, -84, -84, 148, -84, - -84, -84, -84, 201, 130, -84, -84, -84, -84, -84, - -84, 343, 67, 62, 122, 109, -84, -84, -84, 85, - 273, -84, 184, -84, 1210, -84, -84, 119, -84, 112, - -84, 521, -84, -84, 1130, -84, 45, 54, 58, 38, - 1290, 50, 521, 521, 521, 376, 521, -84, -84, 521, - 521, 521, -84, -84, 25, -84, 521, 521, -84, 43, - 521, -84, 521, 18, 15, -84, -84, -84, 24, -84, - -84, 521, 521, 64, 153, 27, -84, 1050, -84, -84, - 521, 521, 521, -84, -84, -84, 28, -84, 37, 55, - 19, -84, 33, -84, 34, 1210, -84, 16, 1210, -84, - -84, 39, 52, -3, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, 521, - -84, 1050, 125, 521, -84, -84, 155, 521, 189, 521, - 521, 521, 521, 248, 521, 521, 521, 521, 521, 521, - 243, 521, 521, 521, 75, 82, 94, 177, 184, 184, - 184, 184, 263, 283, 298, 521, 44, 521, 77, -84, - 970, 521, 817, -84, -84, -84, 95, 521, -84, -84, - 93, -84, -84, 521, -84, -84, -84, -84, 521, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, 521, 41, 521, 521, 68, 66, 521, -84, - -84, 970, 521, -84, 103, -84, -84, -84, 63, -84, - -84, -84, -84, 69, -84, -84, -84, -84, -27, 12, - 521, 92, 100, -84, -84, 890, -84, 31, -13, -45, - -84, 210, 32, -28, 387, 20, 73, 304, 117, -5, - 521, 212, 521, 521, 521, 521, 213, 521, 521, 521, - 521, 521, 151, 150, 176, 158, 168, 304, 304, 228, - 521, -72, 521, 4, 521, -84, 306, 521, -84, 521, - 8, -50, 521, -48, 1130, -84, 521, 80, 1130, -84, - 521, -33, 521, 521, 5, 48, 521, -84, 17, 88, - 11, -84, -84, 521, -84, -29, 521, -84, -41, 521, - -39, 1130, -84, 521, 87, 1130, -84, -8, -2, -35, - 10, 1210, -16, -84, 1130, -84, 521, 86, 1130, -14, - 1130, -84, -84, 1130, -36, 107, -21, 165, 3, 521, - 1130, 6, 14, 61, 7, -19, 448, -4, -6, 671, - 29, 13, 23, 521, 30, -10, 521, 9, 521, -30, - -18, -84, -84, 164, -84, -84, 46, -84, -84, 521, - 111, -24, -84, 36, -84, 40, 99, 521, -84, 21, - 22, -84, -11, -84, 1130, -84, 106, 1130, -84, 178, - -84, -84, 98, 1130, 57, -84, 56, 60, -84, 51, - 26, 35, -84, -84, -84, -84, 521, 97, 1130, -84, - 521, 90, 1130, -84, 79, 76, 744, -84, 49, -84, - 594, -84, -84, -84, -84, -84, 83, -84, -84, -84, - -84, -84, -84, -84, 42, -84, 162, -84, -84, 521, - -84, -84, 53, -84, -84, - - -61, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -4, -88, -88, 22, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -51, -88, -88, -88, -88, -88, - -88, 105, -88, -88, -12, -88, -88, -88, -88, -88, - -7, -88, 35, 132, 62, 154, 79, -88, -88, 100, - 75, 36, -88, -88, -88, -88, 37, 70, -88, -1, - 86, -88, 92, -88, -88, -88, -88, -88, -88, -88, - -88, 90, 95, -88, -88, -88, -88, -88, -88, -88, - 87, 82, 74, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -47, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, 28, - -88, 20, -88, 19, -88, -88, -88, 39, -88, 42, - 43, 106, 61, -88, 63, 55, 52, 53, 91, 125, - -88, 120, 123, 118, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, 116, -88, 59, -88, -88, - 16, 18, 15, -88, -88, -88, -88, 21, -88, -88, - -88, -88, -88, 24, -88, -88, -88, -88, 38, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, 97, -88, 115, 25, -88, -88, 26, -88, - -88, 111, 14, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - 23, -88, -88, -88, -88, 108, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - 160, -88, 171, 163, 145, 179, -88, 135, 45, 41, - 66, 80, -88, -88, -88, -88, -88, -88, -88, -88, - 172, -88, 156, -88, 142, -88, -88, 144, -88, 122, - -88, -88, 114, -88, -23, -88, 48, -88, 29, -88, - 224, -88, 157, 175, -88, -88, 182, -88, -88, -88, - -88, -88, -88, 183, -88, -21, 134, -88, -88, 49, - -88, 3, -88, 44, -88, 2, -88, -88, -37, -88, - -88, -31, -88, -88, 10, -88, 47, -88, 17, -88, - 27, -88, -88, 13, -88, -88, -88, -88, -88, 117, - 6, -88, -88, -88, -88, -88, 154, -88, -88, 1, - -88, -88, -88, 7, -88, -35, 137, -88, 141, -88, - -88, -88, -88, -6, -88, -88, -88, -88, -88, 78, - -88, -88, -88, -88, -88, -69, -88, 11, -88, -59, - -88, -88, -88, -88, 83, -88, -88, 56, -88, -88, - -88, -88, -88, -40, -58, -88, -88, -29, -88, -88, - -88, -45, -88, -88, -88, -88, -3, -88, -42, -88, - -5, -88, -32, -88, -88, -88, 9, -88, 8, -88, - -2, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, 12, - -88, -88, -56, -88, -88}; - -const int QScriptGrammar::action_info [] = { - 318, -25, 350, -45, 292, 270, 426, 310, -194, 393, - -32, 302, 304, -37, 344, 290, 197, 346, 430, 382, - 329, 331, 310, 413, 318, 340, 397, 101, 338, 404, - -49, 292, 270, 299, 323, 290, -24, -51, -195, 343, - 294, 397, 333, 341, 403, 397, 149, 249, 250, 389, - 255, 430, 155, 454, 426, 316, 97, 437, 437, 459, - 151, 389, 103, 102, 98, 344, 101, 105, 413, 222, - 222, 109, 157, 228, 346, 187, 413, 417, 157, 104, - 420, 255, 454, 337, 443, 236, 421, 438, 197, 185, - 97, 197, 419, 413, 197, 197, 325, -263, 197, 81, - 197, 203, 0, 197, 416, 197, 88, 388, 387, 400, - 82, 197, 224, 407, 197, 81, 225, 89, 417, 197, - 187, 90, 81, 312, 241, 240, 82, 313, 0, 0, - 246, 245, 153, 82, 81, 439, 238, 231, 197, 0, - 308, 243, 171, 447, 172, 82, 348, 335, 238, 326, - 432, 198, 252, 204, 401, 173, 232, 428, 192, 235, - 0, 254, 253, 190, 0, 90, 91, 90, 239, 237, - 462, 391, 92, 244, 242, 171, 171, 172, 172, 231, - 239, 237, 191, 171, 192, 172, 197, 0, 173, 173, - 0, 207, 206, 171, 243, 172, 173, 0, 232, 0, - 192, 171, 171, 172, 172, 0, 173, 159, 160, 171, - 91, 172, 91, 0, 173, 173, 92, 0, 92, 159, - 160, 0, 173, 463, 461, 0, 244, 242, 272, 273, - 272, 273, 0, 0, 161, 162, 277, 278, 0, 411, - 410, 0, 0, 0, 0, 279, 161, 162, 280, 0, - 281, 277, 278, 0, 0, 274, 275, 274, 275, 0, - 279, 0, 0, 280, 0, 281, 0, 0, 171, 0, - 172, 164, 165, 0, 0, 0, 0, 0, 0, 166, - 167, 173, 0, 168, 0, 169, 164, 165, 0, 0, - 0, 0, 0, 0, 166, 167, 164, 165, 168, 0, - 169, 0, 0, 0, 166, 167, 164, 165, 168, 209, - 169, 0, 0, 0, 166, 167, 0, 0, 168, 210, - 169, 164, 165, 211, 0, 0, 0, 277, 278, 166, - 167, 0, 212, 168, 213, 169, 279, 0, 0, 280, - 0, 281, 0, 0, 0, 214, 209, 215, 88, 0, - 0, 0, 0, 0, 0, 216, 210, 0, 217, 89, - 211, 0, 0, 0, 218, 0, 0, 0, 0, 212, - 219, 213, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 214, 220, 215, 88, 0, 0, 42, 43, - 209, 0, 216, 0, 0, 217, 89, 0, 85, 0, - 210, 218, 0, 0, 211, 86, 0, 219, 0, 87, - 51, 0, 52, 212, 0, 213, 0, 0, 306, 55, - 220, 0, 0, 58, 0, 0, 214, 0, 215, 88, - 0, 0, 0, 0, 0, 0, 216, 0, 0, 217, - 89, 63, 0, 65, 0, 218, 0, 0, 0, 0, - 0, 219, 0, 0, 57, 68, 45, 0, 0, 0, - 42, 43, 0, 0, 220, 0, 0, 0, 0, 0, - 85, 0, 0, 0, 0, 0, 0, 86, 0, 0, - 0, 87, 51, 0, 52, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 0, 58, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 63, 0, 65, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 57, 68, 45, 0, - 0, 0, 41, 42, 43, 0, 0, 0, 0, 0, - 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, - 86, 0, 0, 0, 87, 51, 0, 52, 0, 0, - 0, 53, 0, 54, 55, 56, 0, 0, 58, 0, - 0, 0, 59, 0, 60, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 63, 0, 65, 0, - 67, 0, 70, 0, 72, 0, 0, 0, 0, 57, - 68, 45, 0, 0, 0, 41, 42, 43, 0, 0, - 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, - 0, 0, 0, 86, 0, 0, 0, 87, 51, 0, - 52, 0, 0, 0, 53, 0, 54, 55, 56, 0, - 0, 58, 0, 0, 0, 59, 0, 60, 0, 0, - 442, 0, 0, 0, 0, 0, 0, 0, 0, 63, - 0, 65, 0, 67, 0, 70, 0, 72, 0, 0, - 0, 0, 57, 68, 45, 0, 0, 0, -47, 0, - 0, 0, 41, 42, 43, 0, 0, 0, 0, 0, - 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, - 86, 0, 0, 0, 87, 51, 0, 52, 0, 0, - 0, 53, 0, 54, 55, 56, 0, 0, 58, 0, - 0, 0, 59, 0, 60, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 63, 0, 65, 0, - 67, 0, 70, 0, 72, 0, 0, 0, 0, 57, - 68, 45, 0, 0, 0, 41, 42, 43, 0, 0, - 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, - 0, 0, 0, 86, 0, 0, 0, 87, 51, 0, - 52, 0, 0, 0, 53, 0, 54, 55, 56, 0, - 0, 58, 0, 0, 0, 59, 0, 60, 0, 0, - 445, 0, 0, 0, 0, 0, 0, 0, 0, 63, - 0, 65, 0, 67, 0, 70, 0, 72, 0, 0, - 0, 0, 57, 68, 45, 0, 0, 0, 41, 42, - 43, 0, 0, 0, 0, 0, 0, 0, 0, 85, - 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, - 87, 51, 0, 52, 0, 0, 0, 53, 0, 54, - 55, 56, 0, 0, 58, 0, 0, 0, 59, 0, - 60, 0, 0, 0, 0, 0, 0, 202, 0, 0, - 0, 0, 63, 0, 65, 0, 67, 0, 70, 0, - 72, 0, 0, 0, 0, 57, 68, 45, 0, 0, - 0, 41, 42, 43, 0, 0, 0, 0, 0, 0, - 0, 0, 85, 0, 0, 0, 0, 0, 0, 86, - 0, 0, 0, 87, 51, 0, 52, 0, 0, 0, - 53, 0, 54, 55, 56, 0, 0, 58, 0, 0, - 0, 59, 0, 60, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 63, 0, 65, 0, 67, - 0, 70, 269, 72, 0, 0, 0, 0, 57, 68, - 45, 0, 0, 0, 115, 116, 117, 0, 0, 119, - 121, 122, 0, 0, 123, 0, 124, 0, 0, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 195, - 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, - 0, 0, 0, 0, 0, 0, 139, 140, 141, 0, - 143, 144, 145, 146, 147, 148, 0, 0, 134, 142, - 125, 118, 120, 136, 115, 116, 117, 0, 0, 119, - 121, 122, 0, 0, 123, 0, 124, 0, 0, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 129, - 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 133, 0, 0, 0, 135, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, - 0, 0, 0, 0, 0, 138, 139, 140, 141, 0, - 143, 144, 145, 146, 147, 148, 0, 0, 134, 142, - 125, 118, 120, 136, 37, 0, 0, 0, 0, 39, - 0, 41, 42, 43, 44, 0, 0, 0, 0, 0, - 0, 46, 85, 0, 0, 0, 0, 0, 0, 48, - 49, 0, 0, 50, 51, 0, 52, 0, 0, 0, - 53, 0, 54, 55, 56, 0, 0, 58, 0, 0, - 0, 59, 0, 60, 0, 0, 0, 0, 0, 61, - 0, 62, 0, 0, 0, 63, 64, 65, 66, 67, - 69, 70, 71, 72, 73, 74, 0, 0, 57, 68, - 45, 38, 40, 0, 37, 0, 0, 0, 0, 39, - 0, 41, 42, 43, 44, 0, 0, 0, 0, 0, - 0, 46, 47, 0, 0, 0, 0, 0, 0, 48, - 49, 0, 0, 50, 51, 0, 52, 0, 0, 0, - 53, 0, 54, 55, 56, 0, 0, 58, 0, 0, - 0, 59, 0, 60, 0, 0, 0, 0, 0, 61, - 0, 62, 0, 0, 0, 63, 64, 65, 66, 67, - 69, 70, 71, 72, 73, 74, 0, 0, 57, 68, - 45, 38, 40, 0, 355, 116, 117, 0, 0, 357, - 121, 359, 42, 43, 360, 0, 124, 0, 0, 0, - 126, 362, 363, 0, 0, 0, 0, 0, 0, 364, - 365, 131, 132, 50, 51, 0, 52, 0, 0, 0, - 53, 0, 54, 366, 56, 0, 0, 368, 0, 0, - 0, 59, 0, 60, 0, -190, 0, 0, 0, 369, - 0, 62, 0, 0, 0, 370, 371, 372, 373, 67, - 375, 376, 377, 378, 379, 380, 0, 0, 367, 374, - 361, 356, 358, 136, - - 431, 422, 427, 429, 441, 352, 300, 398, 385, 464, - 440, 412, 409, 433, 402, 444, 406, 423, 460, 234, - 418, 201, 305, 196, 34, 154, 194, 199, 251, 152, - 205, 227, 229, 248, 150, 110, 230, 208, 352, 110, - 446, 300, 409, 339, 221, 412, 327, 336, 332, 334, - 342, 248, 347, 307, 300, 345, 0, 83, 381, 83, - 83, 83, 349, 83, 284, 158, 163, 182, 283, 0, - 83, 83, 351, 83, 309, 178, 179, 83, 177, 83, - 83, 83, 449, 390, 83, 184, 170, 188, 83, 285, - 453, 330, 83, 83, 95, 452, 0, 83, 83, 450, - 83, 352, 94, 286, 83, 83, 424, 93, 83, 83, - 83, 84, 425, 83, 180, 83, 156, 408, 83, 300, - 451, 194, 233, 83, 83, 247, 264, 300, 352, 223, - 183, 268, 0, 83, 83, 83, 83, 247, 83, 300, - 176, 83, 174, 83, 405, 175, 186, 0, 181, 226, - 83, 0, 448, 83, 0, 83, 303, 424, 282, 83, - 296, 425, 296, 83, 301, 268, 383, 268, 268, 384, - 288, 0, 0, 0, 83, 83, 328, 0, 83, 268, - 268, 83, 295, 268, 298, 293, 268, 271, 287, 83, - 83, 0, 314, 296, 268, 268, 276, 83, 268, 0, - 296, 296, 268, 291, 289, 268, 268, 0, 0, 0, - 0, 0, 0, 0, 0, 315, 0, 0, 0, 0, - 0, 0, 317, 324, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 83, 0, 0, 0, 0, 268, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 311, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0}; - -const int QScriptGrammar::action_check [] = { - 29, 7, 16, 7, 76, 1, 36, 2, 29, 33, - 7, 61, 60, 7, 7, 48, 8, 36, 36, 55, - 61, 60, 2, 33, 29, 60, 5, 29, 36, 7, - 7, 76, 1, 61, 17, 48, 7, 7, 29, 55, - 8, 5, 31, 33, 55, 5, 7, 74, 36, 36, - 36, 36, 55, 29, 36, 7, 29, 8, 8, 17, - 8, 36, 29, 8, 36, 7, 29, 33, 33, 2, - 2, 55, 1, 7, 36, 76, 33, 20, 1, 60, - 29, 36, 29, 29, 8, 0, 60, 8, 8, 48, - 29, 8, 36, 33, 8, 8, 8, 36, 8, 40, - 8, 8, -1, 8, 6, 8, 42, 61, 62, 10, - 51, 8, 50, 7, 8, 40, 54, 53, 20, 8, - 76, 12, 40, 50, 61, 62, 51, 54, -1, -1, - 61, 62, 7, 51, 40, 56, 29, 15, 8, -1, - 60, 29, 25, 60, 27, 51, 60, 60, 29, 61, - 60, 56, 60, 60, 55, 38, 34, 60, 36, 56, - -1, 61, 62, 15, -1, 12, 57, 12, 61, 62, - 8, 60, 63, 61, 62, 25, 25, 27, 27, 15, - 61, 62, 34, 25, 36, 27, 8, -1, 38, 38, - -1, 61, 62, 25, 29, 27, 38, -1, 34, -1, - 36, 25, 25, 27, 27, -1, 38, 18, 19, 25, - 57, 27, 57, -1, 38, 38, 63, -1, 63, 18, - 19, -1, 38, 61, 62, -1, 61, 62, 18, 19, - 18, 19, -1, -1, 45, 46, 23, 24, -1, 61, - 62, -1, -1, -1, -1, 32, 45, 46, 35, -1, - 37, 23, 24, -1, -1, 45, 46, 45, 46, -1, - 32, -1, -1, 35, -1, 37, -1, -1, 25, -1, - 27, 23, 24, -1, -1, -1, -1, -1, -1, 31, - 32, 38, -1, 35, -1, 37, 23, 24, -1, -1, - -1, -1, -1, -1, 31, 32, 23, 24, 35, -1, - 37, -1, -1, -1, 31, 32, 23, 24, 35, 3, - 37, -1, -1, -1, 31, 32, -1, -1, 35, 13, - 37, 23, 24, 17, -1, -1, -1, 23, 24, 31, - 32, -1, 26, 35, 28, 37, 32, -1, -1, 35, - -1, 37, -1, -1, -1, 39, 3, 41, 42, -1, - -1, -1, -1, -1, -1, 49, 13, -1, 52, 53, - 17, -1, -1, -1, 58, -1, -1, -1, -1, 26, - 64, 28, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 39, 77, 41, 42, -1, -1, 12, 13, - 3, -1, 49, -1, -1, 52, 53, -1, 22, -1, - 13, 58, -1, -1, 17, 29, -1, 64, -1, 33, - 34, -1, 36, 26, -1, 28, -1, -1, 31, 43, - 77, -1, -1, 47, -1, -1, 39, -1, 41, 42, - -1, -1, -1, -1, -1, -1, 49, -1, -1, 52, - 53, 65, -1, 67, -1, 58, -1, -1, -1, -1, - -1, 64, -1, -1, 78, 79, 80, -1, -1, -1, - 12, 13, -1, -1, 77, -1, -1, -1, -1, -1, - 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, - -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 65, -1, 67, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 78, 79, 80, -1, - -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 65, -1, 67, -1, - 69, -1, 71, -1, 73, -1, -1, -1, -1, 78, - 79, 80, -1, -1, -1, 11, 12, 13, -1, -1, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, - 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, - -1, 67, -1, 69, -1, 71, -1, 73, -1, -1, - -1, -1, 78, 79, 80, -1, -1, -1, 7, -1, - -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 65, -1, 67, -1, - 69, -1, 71, -1, 73, -1, -1, -1, -1, 78, - 79, 80, -1, -1, -1, 11, 12, 13, -1, -1, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, - 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, - -1, 67, -1, 69, -1, 71, -1, 73, -1, -1, - -1, -1, 78, 79, 80, -1, -1, -1, 11, 12, - 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, - -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, - 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, -1, -1, -1, -1, -1, 60, -1, -1, - -1, -1, 65, -1, 67, -1, 69, -1, 71, -1, - 73, -1, -1, -1, -1, 78, 79, 80, -1, -1, - -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, - -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, - -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 65, -1, 67, -1, 69, - -1, 71, 72, 73, -1, -1, -1, -1, 78, 79, - 80, -1, -1, -1, 4, 5, 6, -1, -1, 9, - 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, - 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, - -1, -1, -1, -1, -1, -1, 66, 67, 68, -1, - 70, 71, 72, 73, 74, 75, -1, -1, 78, 79, - 80, 81, 82, 83, 4, 5, 6, -1, -1, 9, - 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, - 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, - -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, - 70, 71, 72, 73, 74, 75, -1, -1, 78, 79, - 80, 81, 82, 83, 4, -1, -1, -1, -1, 9, - -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, - -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, - -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, -1, -1, 78, 79, - 80, 81, 82, -1, 4, -1, -1, -1, -1, 9, - -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, - -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, - -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, -1, -1, 78, 79, - 80, 81, 82, -1, 4, 5, 6, -1, -1, 9, - 10, 11, 12, 13, 14, -1, 16, -1, -1, -1, - 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, 31, 32, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, 55, -1, -1, -1, 59, - -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, -1, -1, 78, 79, - 80, 81, 82, 83, - - 5, 46, 5, 45, 6, 45, 5, 76, 14, 65, - 2, 46, 5, 45, 73, 6, 5, 46, 6, 5, - 78, 6, 45, 5, 85, 6, 10, 6, 5, 9, - 6, 6, 6, 45, 6, 86, 14, 41, 45, 86, - 5, 5, 5, 80, 6, 46, 67, 45, 45, 5, - 81, 45, 5, 5, 5, 45, -1, 18, 45, 18, - 18, 18, 45, 18, 23, 26, 24, 24, 23, -1, - 18, 18, 45, 18, 45, 23, 23, 18, 23, 18, - 18, 18, 20, 5, 18, 24, 23, 28, 18, 23, - 20, 42, 18, 18, 20, 20, -1, 18, 18, 20, - 18, 45, 20, 23, 18, 18, 20, 20, 18, 18, - 18, 21, 20, 18, 23, 18, 21, 61, 18, 5, - 20, 10, 11, 18, 18, 20, 18, 5, 45, 32, - 24, 23, -1, 18, 18, 18, 18, 20, 18, 5, - 22, 18, 22, 18, 61, 22, 30, -1, 23, 34, - 18, -1, 20, 18, -1, 18, 42, 20, 23, 18, - 18, 20, 18, 18, 42, 23, 12, 23, 23, 15, - 25, -1, -1, -1, 18, 18, 42, -1, 18, 23, - 23, 18, 40, 23, 40, 29, 23, 27, 25, 18, - 18, -1, 35, 18, 23, 23, 25, 18, 23, -1, - 18, 18, 23, 31, 25, 23, 23, -1, -1, -1, - -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, - -1, -1, 40, 40, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 18, -1, -1, -1, -1, 23, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1}; - - -#define Q_SCRIPT_REGEXPLITERAL_RULE1 7 - -#define Q_SCRIPT_REGEXPLITERAL_RULE2 8 - -#include "translator.h" - -#include <QtCore/qdebug.h> -#include <QtCore/qnumeric.h> -#include <QtCore/qstring.h> -#include <QtCore/qtextcodec.h> -#include <QtCore/qvariant.h> - -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -QT_BEGIN_NAMESPACE - -static void recordMessage( - Translator *tor, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool plural, const QString &fileName, int lineNo) -{ - TranslatorMessage msg( - context, text, comment, QString(), - fileName, lineNo, QStringList(), - TranslatorMessage::Unfinished, plural); - msg.setExtraComment(extracomment.simplified()); - tor->replace(msg); -} - - -namespace QScript -{ - -class Lexer -{ -public: - Lexer(); - ~Lexer(); - - void setCode(const QString &c, int lineno); - int lex(); - - int currentLineNo() const { return yylineno; } - int currentColumnNo() const { return yycolumn; } - - int startLineNo() const { return startlineno; } - int startColumnNo() const { return startcolumn; } - - int endLineNo() const { return currentLineNo(); } - int endColumnNo() const - { int col = currentColumnNo(); return (col > 0) ? col - 1 : col; } - - bool prevTerminator() const { return terminator; } - - enum State { Start, - Identifier, - InIdentifier, - InSingleLineComment, - InMultiLineComment, - InNum, - InNum0, - InHex, - InOctal, - InDecimal, - InExponentIndicator, - InExponent, - Hex, - Octal, - Number, - String, - Eof, - InString, - InEscapeSequence, - InHexEscape, - InUnicodeEscape, - Other, - Bad }; - - enum Error { - NoError, - IllegalCharacter, - UnclosedStringLiteral, - IllegalEscapeSequence, - IllegalUnicodeEscapeSequence, - UnclosedComment, - IllegalExponentIndicator, - IllegalIdentifier - }; - - enum ParenthesesState { - IgnoreParentheses, - CountParentheses, - BalancedParentheses - }; - - enum RegExpBodyPrefix { - NoPrefix, - EqualPrefix - }; - - bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); - - QString pattern; - int flags; - - State lexerState() const - { return state; } - - QString errorMessage() const - { return errmsg; } - void setErrorMessage(const QString &err) - { errmsg = err; } - void setErrorMessage(const char *err) - { setErrorMessage(QString::fromLatin1(err)); } - - Error error() const - { return err; } - void clearError() - { err = NoError; } - -private: - int yylineno; - bool done; - char *buffer8; - QChar *buffer16; - uint size8, size16; - uint pos8, pos16; - bool terminator; - bool restrKeyword; - // encountered delimiter like "'" and "}" on last run - bool delimited; - int stackToken; - - State state; - void setDone(State s); - uint pos; - void shift(uint p); - int lookupKeyword(const char *); - - bool isWhiteSpace() const; - bool isLineTerminator() const; - bool isHexDigit(ushort c) const; - bool isOctalDigit(ushort c) const; - - int matchPunctuator(ushort c1, ushort c2, - ushort c3, ushort c4); - ushort singleEscape(ushort c) const; - ushort convertOctal(ushort c1, ushort c2, - ushort c3) const; -public: - static unsigned char convertHex(ushort c1); - static unsigned char convertHex(ushort c1, ushort c2); - static QChar convertUnicode(ushort c1, ushort c2, - ushort c3, ushort c4); - static bool isIdentLetter(ushort c); - static bool isDecimalDigit(ushort c); - - inline int ival() const { return qsyylval.toInt(); } - inline double dval() const { return qsyylval.toDouble(); } - inline QString ustr() const { return qsyylval.toString(); } - inline QVariant val() const { return qsyylval; } - - const QChar *characterBuffer() const { return buffer16; } - int characterCount() const { return pos16; } - -private: - void record8(ushort c); - void record16(QChar c); - void recordStartPos(); - - int findReservedWord(const QChar *buffer, int size) const; - - void syncProhibitAutomaticSemicolon(); - - const QChar *code; - uint length; - int yycolumn; - int startlineno; - int startcolumn; - int bol; // begin of line - - QVariant qsyylval; - - // current and following unicode characters - ushort current, next1, next2, next3; - - struct keyword { - const char *name; - int token; - }; - - QString errmsg; - Error err; - - bool wantRx; - bool check_reserved; - - ParenthesesState parenthesesState; - int parenthesesCount; - bool prohibitAutomaticSemicolon; -}; - -} // namespace QScript - -extern double qstrtod(const char *s00, char const **se, bool *ok); - -#define shiftWindowsLineBreak() if(current == '\r' && next1 == '\n') shift(1); - -namespace QScript { - -static int toDigit(char c) -{ - if ((c >= '0') && (c <= '9')) - return c - '0'; - else if ((c >= 'a') && (c <= 'z')) - return 10 + c - 'a'; - else if ((c >= 'A') && (c <= 'Z')) - return 10 + c - 'A'; - return -1; -} - -double integerFromString(const char *buf, int size, int radix) -{ - if (size == 0) - return qSNaN(); - - double sign = 1.0; - int i = 0; - if (buf[0] == '+') { - ++i; - } else if (buf[0] == '-') { - sign = -1.0; - ++i; - } - - if (((size-i) >= 2) && (buf[i] == '0')) { - if (((buf[i+1] == 'x') || (buf[i+1] == 'X')) - && (radix < 34)) { - if ((radix != 0) && (radix != 16)) - return 0; - radix = 16; - i += 2; - } else { - if (radix == 0) { - radix = 8; - ++i; - } - } - } else if (radix == 0) { - radix = 10; - } - - int j = i; - for ( ; i < size; ++i) { - int d = toDigit(buf[i]); - if ((d == -1) || (d >= radix)) - break; - } - double result; - if (j == i) { - if (!qstrcmp(buf, "Infinity")) - result = qInf(); - else - result = qSNaN(); - } else { - result = 0; - double multiplier = 1; - for (--i ; i >= j; --i, multiplier *= radix) - result += toDigit(buf[i]) * multiplier; - } - result *= sign; - return result; -} - -} // namespace QScript - -QScript::Lexer::Lexer() - : - yylineno(0), - size8(128), size16(128), restrKeyword(false), - stackToken(-1), pos(0), - code(0), length(0), - bol(true), - current(0), next1(0), next2(0), next3(0), - err(NoError), - check_reserved(true), - parenthesesState(IgnoreParentheses), - prohibitAutomaticSemicolon(false) -{ - // allocate space for read buffers - buffer8 = new char[size8]; - buffer16 = new QChar[size16]; - flags = 0; - -} - -QScript::Lexer::~Lexer() -{ - delete [] buffer8; - delete [] buffer16; -} - -void QScript::Lexer::setCode(const QString &c, int lineno) -{ - errmsg = QString(); - yylineno = lineno; - yycolumn = 1; - restrKeyword = false; - delimited = false; - stackToken = -1; - pos = 0; - code = c.unicode(); - length = c.length(); - bol = true; - - // read first characters - current = (length > 0) ? code[0].unicode() : 0; - next1 = (length > 1) ? code[1].unicode() : 0; - next2 = (length > 2) ? code[2].unicode() : 0; - next3 = (length > 3) ? code[3].unicode() : 0; -} - -void QScript::Lexer::shift(uint p) -{ - while (p--) { - ++pos; - ++yycolumn; - current = next1; - next1 = next2; - next2 = next3; - next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0; - } -} - -void QScript::Lexer::setDone(State s) -{ - state = s; - done = true; -} - -int QScript::Lexer::findReservedWord(const QChar *c, int size) const -{ - switch (size) { - case 2: { - if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')) - return QScriptGrammar::T_DO; - else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f')) - return QScriptGrammar::T_IF; - else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')) - return QScriptGrammar::T_IN; - } break; - - case 3: { - if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r')) - return QScriptGrammar::T_FOR; - else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w')) - return QScriptGrammar::T_NEW; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y')) - return QScriptGrammar::T_TRY; - else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r')) - return QScriptGrammar::T_VAR; - else if (check_reserved) { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 4: { - if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_CASE; - else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_ELSE; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s')) - return QScriptGrammar::T_THIS; - else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d')) - return QScriptGrammar::T_VOID; - else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h')) - return QScriptGrammar::T_WITH; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_TRUE; - else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l')) - return QScriptGrammar::T_NULL; - else if (check_reserved) { - if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n') - && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 5: { - if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('k')) - return QScriptGrammar::T_BREAK; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c') - && c[4] == QLatin1Char('h')) - return QScriptGrammar::T_CATCH; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('w')) - return QScriptGrammar::T_THROW; - else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('e')) - return QScriptGrammar::T_WHILE; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s') - && c[4] == QLatin1Char('t')) - return QScriptGrammar::T_CONST; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s') - && c[4] == QLatin1Char('e')) - return QScriptGrammar::T_FALSE; - else if (check_reserved) { - if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r') - && c[4] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('r')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('l')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s') - && c[4] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 6: { - if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e')) - return QScriptGrammar::T_DELETE; - else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n')) - return QScriptGrammar::T_RETURN; - else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h')) - return QScriptGrammar::T_SWITCH; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f')) - return QScriptGrammar::T_TYPEOF; - else if (check_reserved) { - if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b') - && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i') - && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 7: { - if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l') - && c[6] == QLatin1Char('t')) - return QScriptGrammar::T_DEFAULT; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l') - && c[6] == QLatin1Char('y')) - return QScriptGrammar::T_FINALLY; - else if (check_reserved) { - if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a') - && c[6] == QLatin1Char('n')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d') - && c[6] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k') - && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g') - && c[6] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v') - && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t') - && c[6] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 8: { - if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n') - && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e')) - return QScriptGrammar::T_CONTINUE; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') - && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') - && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')) - return QScriptGrammar::T_FUNCTION; - else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u') - && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g') - && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r')) - return QScriptGrammar::T_DEBUGGER; - else if (check_reserved) { - if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a') - && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') - && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 9: { - if (check_reserved) { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f') - && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c') - && c[8] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n') - && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i') - && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') - && c[8] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c') - && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e') - && c[8] == QLatin1Char('d')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 10: { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n') - && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e') - && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f')) - return QScriptGrammar::T_INSTANCEOF; - else if (check_reserved) { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m') - && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') - && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 12: { - if (check_reserved) { - if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') - && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r') - && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n') - && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z') - && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - } // switch - - return -1; -} - -int QScript::Lexer::lex() -{ - int token = 0; - state = Start; - ushort stringType = 0; // either single or double quotes - pos8 = pos16 = 0; - done = false; - terminator = false; - - // did we push a token on the stack previously ? - // (after an automatic semicolon insertion) - if (stackToken >= 0) { - setDone(Other); - token = stackToken; - stackToken = -1; - } - - while (!done) { - switch (state) { - case Start: - if (isWhiteSpace()) { - // do nothing - } else if (current == '/' && next1 == '/') { - recordStartPos(); - shift(1); - state = InSingleLineComment; - } else if (current == '/' && next1 == '*') { - recordStartPos(); - shift(1); - state = InMultiLineComment; - } else if (current == 0) { - syncProhibitAutomaticSemicolon(); - if (!terminator && !delimited && !prohibitAutomaticSemicolon) { - // automatic semicolon insertion if program incomplete - token = QScriptGrammar::T_SEMICOLON; - stackToken = 0; - setDone(Other); - } else { - setDone(Eof); - } - } else if (isLineTerminator()) { - shiftWindowsLineBreak(); - yylineno++; - yycolumn = 0; - bol = true; - terminator = true; - syncProhibitAutomaticSemicolon(); - if (restrKeyword) { - token = QScriptGrammar::T_SEMICOLON; - setDone(Other); - } - } else if (current == '"' || current == '\'') { - recordStartPos(); - state = InString; - stringType = current; - } else if (isIdentLetter(current)) { - recordStartPos(); - record16(current); - state = InIdentifier; - } else if (current == '0') { - recordStartPos(); - record8(current); - state = InNum0; - } else if (isDecimalDigit(current)) { - recordStartPos(); - record8(current); - state = InNum; - } else if (current == '.' && isDecimalDigit(next1)) { - recordStartPos(); - record8(current); - state = InDecimal; - } else { - recordStartPos(); - token = matchPunctuator(current, next1, next2, next3); - if (token != -1) { - if (terminator && !delimited && !prohibitAutomaticSemicolon - && (token == QScriptGrammar::T_PLUS_PLUS - || token == QScriptGrammar::T_MINUS_MINUS)) { - // automatic semicolon insertion - stackToken = token; - token = QScriptGrammar::T_SEMICOLON; - } - setDone(Other); - } - else { - setDone(Bad); - err = IllegalCharacter; - errmsg = QLatin1String("Illegal character"); - } - } - break; - case InString: - if (current == stringType) { - shift(1); - setDone(String); - } else if (current == 0 || isLineTerminator()) { - setDone(Bad); - err = UnclosedStringLiteral; - errmsg = QLatin1String("Unclosed string at end of line"); - } else if (current == '\\') { - state = InEscapeSequence; - } else { - record16(current); - } - break; - // Escape Sequences inside of strings - case InEscapeSequence: - if (isOctalDigit(current)) { - if (current >= '0' && current <= '3' && - isOctalDigit(next1) && isOctalDigit(next2)) { - record16(convertOctal(current, next1, next2)); - shift(2); - state = InString; - } else if (isOctalDigit(current) && - isOctalDigit(next1)) { - record16(convertOctal('0', current, next1)); - shift(1); - state = InString; - } else if (isOctalDigit(current)) { - record16(convertOctal('0', '0', current)); - state = InString; - } else { - setDone(Bad); - err = IllegalEscapeSequence; - errmsg = QLatin1String("Illegal escape squence"); - } - } else if (current == 'x') - state = InHexEscape; - else if (current == 'u') - state = InUnicodeEscape; - else { - record16(singleEscape(current)); - state = InString; - } - break; - case InHexEscape: - if (isHexDigit(current) && isHexDigit(next1)) { - state = InString; - record16(QLatin1Char(convertHex(current, next1))); - shift(1); - } else if (current == stringType) { - record16(QLatin1Char('x')); - shift(1); - setDone(String); - } else { - record16(QLatin1Char('x')); - record16(current); - state = InString; - } - break; - case InUnicodeEscape: - if (isHexDigit(current) && isHexDigit(next1) && - isHexDigit(next2) && isHexDigit(next3)) { - record16(convertUnicode(current, next1, next2, next3)); - shift(3); - state = InString; - } else if (current == stringType) { - record16(QLatin1Char('u')); - shift(1); - setDone(String); - } else { - setDone(Bad); - err = IllegalUnicodeEscapeSequence; - errmsg = QLatin1String("Illegal unicode escape sequence"); - } - break; - case InSingleLineComment: - if (isLineTerminator()) { - shiftWindowsLineBreak(); - yylineno++; - yycolumn = 0; - terminator = true; - bol = true; - if (restrKeyword) { - token = QScriptGrammar::T_SEMICOLON; - setDone(Other); - } else - state = Start; - } else if (current == 0) { - setDone(Eof); - } - break; - case InMultiLineComment: - if (current == 0) { - setDone(Bad); - err = UnclosedComment; - errmsg = QLatin1String("Unclosed comment at end of file"); - } else if (isLineTerminator()) { - shiftWindowsLineBreak(); - yylineno++; - } else if (current == '*' && next1 == '/') { - state = Start; - shift(1); - } - break; - case InIdentifier: - if (isIdentLetter(current) || isDecimalDigit(current)) { - record16(current); - break; - } - setDone(Identifier); - break; - case InNum0: - if (current == 'x' || current == 'X') { - record8(current); - state = InHex; - } else if (current == '.') { - record8(current); - state = InDecimal; - } else if (current == 'e' || current == 'E') { - record8(current); - state = InExponentIndicator; - } else if (isOctalDigit(current)) { - record8(current); - state = InOctal; - } else if (isDecimalDigit(current)) { - record8(current); - state = InDecimal; - } else { - setDone(Number); - } - break; - case InHex: - if (isHexDigit(current)) - record8(current); - else - setDone(Hex); - break; - case InOctal: - if (isOctalDigit(current)) { - record8(current); - } else if (isDecimalDigit(current)) { - record8(current); - state = InDecimal; - } else { - setDone(Octal); - } - break; - case InNum: - if (isDecimalDigit(current)) { - record8(current); - } else if (current == '.') { - record8(current); - state = InDecimal; - } else if (current == 'e' || current == 'E') { - record8(current); - state = InExponentIndicator; - } else { - setDone(Number); - } - break; - case InDecimal: - if (isDecimalDigit(current)) { - record8(current); - } else if (current == 'e' || current == 'E') { - record8(current); - state = InExponentIndicator; - } else { - setDone(Number); - } - break; - case InExponentIndicator: - if (current == '+' || current == '-') { - record8(current); - } else if (isDecimalDigit(current)) { - record8(current); - state = InExponent; - } else { - setDone(Bad); - err = IllegalExponentIndicator; - errmsg = QLatin1String("Illegal syntax for exponential number"); - } - break; - case InExponent: - if (isDecimalDigit(current)) { - record8(current); - } else { - setDone(Number); - } - break; - default: - Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement"); - } - - // move on to the next character - if (!done) - shift(1); - if (state != Start && state != InSingleLineComment) - bol = false; - } - - // no identifiers allowed directly after numeric literal, e.g. "3in" is bad - if ((state == Number || state == Octal || state == Hex) - && isIdentLetter(current)) { - state = Bad; - err = IllegalIdentifier; - errmsg = QLatin1String("Identifier cannot start with numeric literal"); - } - - // terminate string - buffer8[pos8] = '\0'; - - double dval = 0; - if (state == Number) { - dval = qstrtod(buffer8, 0, 0); - } else if (state == Hex) { // scan hex numbers - dval = QScript::integerFromString(buffer8, pos8, 16); - state = Number; - } else if (state == Octal) { // scan octal number - dval = QScript::integerFromString(buffer8, pos8, 8); - state = Number; - } - - restrKeyword = false; - delimited = false; - - switch (parenthesesState) { - case IgnoreParentheses: - break; - case CountParentheses: - if (token == QScriptGrammar::T_RPAREN) { - --parenthesesCount; - if (parenthesesCount == 0) - parenthesesState = BalancedParentheses; - } else if (token == QScriptGrammar::T_LPAREN) { - ++parenthesesCount; - } - break; - case BalancedParentheses: - parenthesesState = IgnoreParentheses; - break; - } - - switch (state) { - case Eof: - return 0; - case Other: - if(token == QScriptGrammar::T_RBRACE || token == QScriptGrammar::T_SEMICOLON) - delimited = true; - return token; - case Identifier: - if ((token = findReservedWord(buffer16, pos16)) < 0) { - /* TODO: close leak on parse error. same holds true for String */ - qsyylval = QString(buffer16, pos16); - return QScriptGrammar::T_IDENTIFIER; - } - if (token == QScriptGrammar::T_CONTINUE || token == QScriptGrammar::T_BREAK - || token == QScriptGrammar::T_RETURN || token == QScriptGrammar::T_THROW) { - restrKeyword = true; - } else if (token == QScriptGrammar::T_IF || token == QScriptGrammar::T_FOR - || token == QScriptGrammar::T_WHILE || token == QScriptGrammar::T_WITH) { - parenthesesState = CountParentheses; - parenthesesCount = 0; - } else if (token == QScriptGrammar::T_DO) { - parenthesesState = BalancedParentheses; - } - return token; - case String: - qsyylval = QString(buffer16, pos16); - return QScriptGrammar::T_STRING_LITERAL; - case Number: - qsyylval = dval; - return QScriptGrammar::T_NUMERIC_LITERAL; - case Bad: - return -1; - default: - Q_ASSERT(!"unhandled numeration value in switch"); - return -1; - } -} - -bool QScript::Lexer::isWhiteSpace() const -{ - return (current == ' ' || current == '\t' || - current == 0x0b || current == 0x0c); -} - -bool QScript::Lexer::isLineTerminator() const -{ - return (current == '\n' || current == '\r'); -} - -bool QScript::Lexer::isIdentLetter(ushort c) -{ - /* TODO: allow other legitimate unicode chars */ - return ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == '$' - || c == '_'); -} - -bool QScript::Lexer::isDecimalDigit(ushort c) -{ - return (c >= '0' && c <= '9'); -} - -bool QScript::Lexer::isHexDigit(ushort c) const -{ - return ((c >= '0' && c <= '9') - || (c >= 'a' && c <= 'f') - || (c >= 'A' && c <= 'F')); -} - -bool QScript::Lexer::isOctalDigit(ushort c) const -{ - return (c >= '0' && c <= '7'); -} - -int QScript::Lexer::matchPunctuator(ushort c1, ushort c2, - ushort c3, ushort c4) -{ - if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { - shift(4); - return QScriptGrammar::T_GT_GT_GT_EQ; - } else if (c1 == '=' && c2 == '=' && c3 == '=') { - shift(3); - return QScriptGrammar::T_EQ_EQ_EQ; - } else if (c1 == '!' && c2 == '=' && c3 == '=') { - shift(3); - return QScriptGrammar::T_NOT_EQ_EQ; - } else if (c1 == '>' && c2 == '>' && c3 == '>') { - shift(3); - return QScriptGrammar::T_GT_GT_GT; - } else if (c1 == '<' && c2 == '<' && c3 == '=') { - shift(3); - return QScriptGrammar::T_LT_LT_EQ; - } else if (c1 == '>' && c2 == '>' && c3 == '=') { - shift(3); - return QScriptGrammar::T_GT_GT_EQ; - } else if (c1 == '<' && c2 == '=') { - shift(2); - return QScriptGrammar::T_LE; - } else if (c1 == '>' && c2 == '=') { - shift(2); - return QScriptGrammar::T_GE; - } else if (c1 == '!' && c2 == '=') { - shift(2); - return QScriptGrammar::T_NOT_EQ; - } else if (c1 == '+' && c2 == '+') { - shift(2); - return QScriptGrammar::T_PLUS_PLUS; - } else if (c1 == '-' && c2 == '-') { - shift(2); - return QScriptGrammar::T_MINUS_MINUS; - } else if (c1 == '=' && c2 == '=') { - shift(2); - return QScriptGrammar::T_EQ_EQ; - } else if (c1 == '+' && c2 == '=') { - shift(2); - return QScriptGrammar::T_PLUS_EQ; - } else if (c1 == '-' && c2 == '=') { - shift(2); - return QScriptGrammar::T_MINUS_EQ; - } else if (c1 == '*' && c2 == '=') { - shift(2); - return QScriptGrammar::T_STAR_EQ; - } else if (c1 == '/' && c2 == '=') { - shift(2); - return QScriptGrammar::T_DIVIDE_EQ; - } else if (c1 == '&' && c2 == '=') { - shift(2); - return QScriptGrammar::T_AND_EQ; - } else if (c1 == '^' && c2 == '=') { - shift(2); - return QScriptGrammar::T_XOR_EQ; - } else if (c1 == '%' && c2 == '=') { - shift(2); - return QScriptGrammar::T_REMAINDER_EQ; - } else if (c1 == '|' && c2 == '=') { - shift(2); - return QScriptGrammar::T_OR_EQ; - } else if (c1 == '<' && c2 == '<') { - shift(2); - return QScriptGrammar::T_LT_LT; - } else if (c1 == '>' && c2 == '>') { - shift(2); - return QScriptGrammar::T_GT_GT; - } else if (c1 == '&' && c2 == '&') { - shift(2); - return QScriptGrammar::T_AND_AND; - } else if (c1 == '|' && c2 == '|') { - shift(2); - return QScriptGrammar::T_OR_OR; - } - - switch(c1) { - case '=': shift(1); return QScriptGrammar::T_EQ; - case '>': shift(1); return QScriptGrammar::T_GT; - case '<': shift(1); return QScriptGrammar::T_LT; - case ',': shift(1); return QScriptGrammar::T_COMMA; - case '!': shift(1); return QScriptGrammar::T_NOT; - case '~': shift(1); return QScriptGrammar::T_TILDE; - case '?': shift(1); return QScriptGrammar::T_QUESTION; - case ':': shift(1); return QScriptGrammar::T_COLON; - case '.': shift(1); return QScriptGrammar::T_DOT; - case '+': shift(1); return QScriptGrammar::T_PLUS; - case '-': shift(1); return QScriptGrammar::T_MINUS; - case '*': shift(1); return QScriptGrammar::T_STAR; - case '/': shift(1); return QScriptGrammar::T_DIVIDE_; - case '&': shift(1); return QScriptGrammar::T_AND; - case '|': shift(1); return QScriptGrammar::T_OR; - case '^': shift(1); return QScriptGrammar::T_XOR; - case '%': shift(1); return QScriptGrammar::T_REMAINDER; - case '(': shift(1); return QScriptGrammar::T_LPAREN; - case ')': shift(1); return QScriptGrammar::T_RPAREN; - case '{': shift(1); return QScriptGrammar::T_LBRACE; - case '}': shift(1); return QScriptGrammar::T_RBRACE; - case '[': shift(1); return QScriptGrammar::T_LBRACKET; - case ']': shift(1); return QScriptGrammar::T_RBRACKET; - case ';': shift(1); return QScriptGrammar::T_SEMICOLON; - - default: return -1; - } -} - -ushort QScript::Lexer::singleEscape(ushort c) const -{ - switch(c) { - case 'b': - return 0x08; - case 't': - return 0x09; - case 'n': - return 0x0A; - case 'v': - return 0x0B; - case 'f': - return 0x0C; - case 'r': - return 0x0D; - case '"': - return 0x22; - case '\'': - return 0x27; - case '\\': - return 0x5C; - default: - return c; - } -} - -ushort QScript::Lexer::convertOctal(ushort c1, ushort c2, - ushort c3) const -{ - return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); -} - -unsigned char QScript::Lexer::convertHex(ushort c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - else if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - else - return (c - 'A' + 10); -} - -unsigned char QScript::Lexer::convertHex(ushort c1, ushort c2) -{ - return ((convertHex(c1) << 4) + convertHex(c2)); -} - -QChar QScript::Lexer::convertUnicode(ushort c1, ushort c2, - ushort c3, ushort c4) -{ - return QChar((convertHex(c3) << 4) + convertHex(c4), - (convertHex(c1) << 4) + convertHex(c2)); -} - -void QScript::Lexer::record8(ushort c) -{ - Q_ASSERT(c <= 0xff); - - // enlarge buffer if full - if (pos8 >= size8 - 1) { - char *tmp = new char[2 * size8]; - memcpy(tmp, buffer8, size8 * sizeof(char)); - delete [] buffer8; - buffer8 = tmp; - size8 *= 2; - } - - buffer8[pos8++] = (char) c; -} - -void QScript::Lexer::record16(QChar c) -{ - // enlarge buffer if full - if (pos16 >= size16 - 1) { - QChar *tmp = new QChar[2 * size16]; - memcpy(tmp, buffer16, size16 * sizeof(QChar)); - delete [] buffer16; - buffer16 = tmp; - size16 *= 2; - } - - buffer16[pos16++] = c; -} - -void QScript::Lexer::recordStartPos() -{ - startlineno = yylineno; - startcolumn = yycolumn; -} - -bool QScript::Lexer::scanRegExp(RegExpBodyPrefix prefix) -{ - pos16 = 0; - bool lastWasEscape = false; - - if (prefix == EqualPrefix) - record16(QLatin1Char('=')); - - while (1) { - if (isLineTerminator() || current == 0) { - errmsg = QLatin1String("Unterminated regular expression literal"); - return false; - } - else if (current != '/' || lastWasEscape == true) - { - record16(current); - lastWasEscape = !lastWasEscape && (current == '\\'); - } - else { - pattern = QString(buffer16, pos16); - pos16 = 0; - shift(1); - break; - } - shift(1); - } - - flags = 0; - while (isIdentLetter(current)) { - record16(current); - shift(1); - } - - return true; -} - -void QScript::Lexer::syncProhibitAutomaticSemicolon() -{ - if (parenthesesState == BalancedParentheses) { - // we have seen something like "if (foo)", which means we should - // never insert an automatic semicolon at this point, since it would - // then be expanded into an empty statement (ECMA-262 7.9.1) - prohibitAutomaticSemicolon = true; - parenthesesState = IgnoreParentheses; - } else { - prohibitAutomaticSemicolon = false; - } -} - - -class Translator; - -class QScriptParser: protected QScriptGrammar -{ -public: - QVariant val; - - struct Location { - int startLine; - int startColumn; - int endLine; - int endColumn; - }; - -public: - QScriptParser(); - ~QScriptParser(); - - bool parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator); - - inline QString errorMessage() const - { return error_message; } - inline int errorLineNumber() const - { return error_lineno; } - inline int errorColumnNumber() const - { return error_column; } - -protected: - inline void reallocateStack(); - - inline QVariant &sym(int index) - { return sym_stack [tos + index - 1]; } - - inline Location &loc(int index) - { return location_stack [tos + index - 2]; } - -protected: - int tos; - int stack_size; - QVector<QVariant> sym_stack; - int *state_stack; - Location *location_stack; - QString error_message; - int error_lineno; - int error_column; -}; - -inline void QScriptParser::reallocateStack() -{ - if (! stack_size) - stack_size = 128; - else - stack_size <<= 1; - - sym_stack.resize(stack_size); - state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); - location_stack = reinterpret_cast<Location*> (qRealloc(location_stack, stack_size * sizeof(Location))); -} - -inline static bool automatic(QScript::Lexer *lexer, int token) -{ - return (token == QScriptGrammar::T_RBRACE) - || (token == 0) - || lexer->prevTerminator(); -} - -QScriptParser::QScriptParser(): - tos(0), - stack_size(0), - sym_stack(0), - state_stack(0), - location_stack(0) -{ -} - -QScriptParser::~QScriptParser() -{ - if (stack_size) { - qFree(state_stack); - qFree(location_stack); - } -} - -static inline QScriptParser::Location location(QScript::Lexer *lexer) -{ - QScriptParser::Location loc; - loc.startLine = lexer->startLineNo(); - loc.startColumn = lexer->startColumnNo(); - loc.endLine = lexer->endLineNo(); - loc.endColumn = lexer->endColumnNo(); - return loc; -} - -bool QScriptParser::parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator) -{ - const int INITIAL_STATE = 0; - - int yytoken = -1; - int saved_yytoken = -1; - int identLineNo = -1; - - reallocateStack(); - - tos = 0; - state_stack[++tos] = INITIAL_STATE; - - while (true) - { - const int state = state_stack [tos]; - if (yytoken == -1 && - TERMINAL_COUNT != action_index [state]) - { - if (saved_yytoken == -1) - { - yytoken = lexer->lex(); - location_stack [tos] = location(lexer); - } - else - { - yytoken = saved_yytoken; - saved_yytoken = -1; - } - } - - int act = t_action (state, yytoken); - - if (act == ACCEPT_STATE) - return true; - - else if (act > 0) - { - if (++tos == stack_size) - reallocateStack(); - - sym_stack [tos] = lexer->val (); - state_stack [tos] = act; - location_stack [tos] = location(lexer); - yytoken = -1; - } - - else if (act < 0) - { - int r = - act - 1; - - tos -= rhs [r]; - act = state_stack [tos++]; - - switch (r) { - -case 1: { - sym(1) = sym(1).toByteArray(); - identLineNo = lexer->startLineNo(); -} break; - -case 7: { - bool rx = lexer->scanRegExp(QScript::Lexer::NoPrefix); - if (!rx) { - error_message = lexer->errorMessage(); - error_lineno = lexer->startLineNo(); - error_column = lexer->startColumnNo(); - return false; - } -} break; - -case 8: { - bool rx = lexer->scanRegExp(QScript::Lexer::EqualPrefix); - if (!rx) { - error_message = lexer->errorMessage(); - error_lineno = lexer->startLineNo(); - error_column = lexer->startColumnNo(); - return false; - } -} break; - -case 66: { - QString name = sym(1).toString(); - if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) { - QVariantList args = sym(2).toList(); - if (args.size() < 2) { - qWarning("%s:%d: %s() requires at least two arguments", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - if ((args.at(0).type() != QVariant::String) - || (args.at(1).type() != QVariant::String)) { - qWarning("%s:%d: %s(): both arguments must be literal strings", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - QString context = args.at(0).toString(); - QString text = args.at(1).toString(); - QString comment = args.value(2).toString(); - QString extracomment; - bool plural = (args.size() > 4); - recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); - } - } - } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) { - QVariantList args = sym(2).toList(); - if (args.size() < 1) { - qWarning("%s:%d: %s() requires at least one argument", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - if (args.at(0).type() != QVariant::String) { - qWarning("%s:%d: %s(): text to translate must be a literal string", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - QString context = QFileInfo(fileName).baseName(); - QString text = args.at(0).toString(); - QString comment = args.value(1).toString(); - QString extracomment; - bool plural = (args.size() > 2); - recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); - } - } - } -} break; - -case 70: { - sym(1) = QVariantList(); -} break; - -case 71: { - sym(1) = sym(2); -} break; - -case 72: { - sym(1) = QVariantList() << sym(1); -} break; - -case 73: { - sym(1) = sym(1).toList() << sym(3); -} break; - -case 94: { - if ((sym(1).type() == QVariant::String) || (sym(3).type() == QVariant::String)) - sym(1) = sym(1).toString() + sym(3).toString(); - else - sym(1) = QVariant(); -} break; - - } // switch - - state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); - - if (rhs[r] > 1) { - location_stack[tos - 1].endLine = location_stack[tos + rhs[r] - 2].endLine; - location_stack[tos - 1].endColumn = location_stack[tos + rhs[r] - 2].endColumn; - location_stack[tos] = location_stack[tos + rhs[r] - 1]; - } - } - - else - { - if (saved_yytoken == -1 && automatic (lexer, yytoken) && t_action (state, T_AUTOMATIC_SEMICOLON) > 0) - { - saved_yytoken = yytoken; - yytoken = T_SEMICOLON; - continue; - } - - else if ((state == INITIAL_STATE) && (yytoken == 0)) { - // accept empty input - yytoken = T_SEMICOLON; - continue; - } - - int ers = state; - int shifts = 0; - int reduces = 0; - int expected_tokens [3]; - for (int tk = 0; tk < TERMINAL_COUNT; ++tk) - { - int k = t_action (ers, tk); - - if (! k) - continue; - else if (k < 0) - ++reduces; - else if (spell [tk]) - { - if (shifts < 3) - expected_tokens [shifts] = tk; - ++shifts; - } - } - - error_message.clear (); - if (shifts && shifts < 3) - { - bool first = true; - - for (int s = 0; s < shifts; ++s) - { - if (first) - error_message += QLatin1String ("Expected "); - else - error_message += QLatin1String (", "); - - first = false; - error_message += QLatin1String("`"); - error_message += QLatin1String (spell [expected_tokens [s]]); - error_message += QLatin1String("'"); - } - } - - if (error_message.isEmpty()) - error_message = lexer->errorMessage(); - - error_lineno = lexer->startLineNo(); - error_column = lexer->startColumnNo(); - - return false; - } - } - - return false; -} - - -bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) -{ - QTextStream ts(&dev); - QByteArray codecName; - if (!cd.m_codecForSource.isEmpty()) - codecName = cd.m_codecForSource; - else - codecName = translator.codecName(); // Just because it should be latin1 already - ts.setCodec(QTextCodec::codecForName(codecName)); - ts.setAutoDetectUnicode(true); - - QString code = ts.readAll(); - QScript::Lexer lexer; - lexer.setCode(code, /*lineNumber=*/1); - QScriptParser parser; - if (!parser.parse(&lexer, cd.m_sourceFileName, &translator)) { - qWarning("%s:%d: %s", qPrintable(cd.m_sourceFileName), parser.errorLineNumber(), - qPrintable(parser.errorMessage())); - return false; - } - - // Java uses UTF-16 internally and Jambi makes UTF-8 for tr() purposes of it. - translator.setCodecName("UTF-8"); - return true; -} - -bool saveQScript(const Translator &translator, QIODevice &dev, ConversionData &cd) -{ - Q_UNUSED(dev); - Q_UNUSED(translator); - cd.appendError(QLatin1String("Cannot save .js files")); - return false; -} - -int initQScript() -{ - Translator::FileFormat format; - format.extension = QLatin1String("js"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("Qt Script source files"); - format.loader = &loadQScript; - format.saver = &saveQScript; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initQScript) - -QT_END_NAMESPACE diff --git a/tools/linguist/shared/qscript.g b/tools/linguist/shared/qscript.g deleted file mode 100644 index 9864cf0..0000000 --- a/tools/linguist/shared/qscript.g +++ /dev/null @@ -1,2039 +0,0 @@ ----------------------------------------------------------------------------- --- --- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). --- Contact: Nokia Corporation (qt-info@nokia.com) --- --- This file is part of the Qt Linguist of the Qt Toolkit. --- --- $QT_BEGIN_LICENSE:LGPL$ --- No Commercial Usage --- This file contains pre-release code and may not be distributed. --- You may use this file in accordance with the terms and conditions --- contained in the Technology Preview License Agreement accompanying --- this package. --- --- GNU Lesser General Public License Usage --- Alternatively, this file may be used under the terms of the GNU Lesser --- General Public License version 2.1 as published by the Free Software --- Foundation and appearing in the file LICENSE.LGPL included in the --- packaging of this file. Please review the following information to --- ensure the GNU Lesser General Public License version 2.1 requirements --- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. --- --- In addition, as a special exception, Nokia gives you certain --- additional rights. These rights are described in the Nokia Qt LGPL --- Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this --- package. --- --- If you have questions regarding the use of this file, please contact --- Nokia at qt-info@nokia.com. --- --- --- --- --- --- --- --- --- $QT_END_LICENSE$ --- --- This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE --- WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. --- ----------------------------------------------------------------------------- - -%parser QScriptGrammar -%merged_output qscript.cpp -%expect 3 -%expect-rr 1 - -%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&=" -%token T_BREAK "break" T_CASE "case" T_CATCH "catch" -%token T_COLON ":" T_COMMA ";" T_CONTINUE "continue" -%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/" -%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "." -%token T_ELSE "else" T_EQ "=" T_EQ_EQ "==" -%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for" -%token T_FUNCTION "function" T_GE ">=" T_GT ">" -%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>" -%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if" -%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{" -%token T_LBRACKET "[" T_LE "<=" T_LPAREN "(" -%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<=" -%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--" -%token T_NEW "new" T_NOT "!" T_NOT_EQ "!=" -%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|" -%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+" -%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?" -%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%" -%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")" -%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*" -%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal" -%token T_SWITCH "switch" T_THIS "this" T_THROW "throw" -%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof" -%token T_VAR "var" T_VOID "void" T_WHILE "while" -%token T_WITH "with" T_XOR "^" T_XOR_EQ "^=" -%token T_NULL "null" T_TRUE "true" T_FALSE "false" -%token T_CONST "const" -%token T_DEBUGGER "debugger" -%token T_RESERVED_WORD "reserved word" - -%start Program - -/. -#include "translator.h" - -#include <QtCore/qdebug.h> -#include <QtCore/qnumeric.h> -#include <QtCore/qstring.h> -#include <QtCore/qtextcodec.h> -#include <QtCore/qvariant.h> - -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -QT_BEGIN_NAMESPACE - -static void recordMessage( - Translator *tor, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool plural, const QString &fileName, int lineNo) -{ - TranslatorMessage msg( - context, text, comment, QString(), - fileName, lineNo, QStringList(), - TranslatorMessage::Unfinished, plural); - msg.setExtraComment(extracomment.simplified()); - tor->replace(msg); -} - - -namespace QScript -{ - -class Lexer -{ -public: - Lexer(); - ~Lexer(); - - void setCode(const QString &c, int lineno); - int lex(); - - int currentLineNo() const { return yylineno; } - int currentColumnNo() const { return yycolumn; } - - int startLineNo() const { return startlineno; } - int startColumnNo() const { return startcolumn; } - - int endLineNo() const { return currentLineNo(); } - int endColumnNo() const - { int col = currentColumnNo(); return (col > 0) ? col - 1 : col; } - - bool prevTerminator() const { return terminator; } - - enum State { Start, - Identifier, - InIdentifier, - InSingleLineComment, - InMultiLineComment, - InNum, - InNum0, - InHex, - InOctal, - InDecimal, - InExponentIndicator, - InExponent, - Hex, - Octal, - Number, - String, - Eof, - InString, - InEscapeSequence, - InHexEscape, - InUnicodeEscape, - Other, - Bad }; - - enum Error { - NoError, - IllegalCharacter, - UnclosedStringLiteral, - IllegalEscapeSequence, - IllegalUnicodeEscapeSequence, - UnclosedComment, - IllegalExponentIndicator, - IllegalIdentifier - }; - - enum ParenthesesState { - IgnoreParentheses, - CountParentheses, - BalancedParentheses - }; - - enum RegExpBodyPrefix { - NoPrefix, - EqualPrefix - }; - - bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); - - QString pattern; - int flags; - - State lexerState() const - { return state; } - - QString errorMessage() const - { return errmsg; } - void setErrorMessage(const QString &err) - { errmsg = err; } - void setErrorMessage(const char *err) - { setErrorMessage(QString::fromLatin1(err)); } - - Error error() const - { return err; } - void clearError() - { err = NoError; } - -private: - int yylineno; - bool done; - char *buffer8; - QChar *buffer16; - uint size8, size16; - uint pos8, pos16; - bool terminator; - bool restrKeyword; - // encountered delimiter like "'" and "}" on last run - bool delimited; - int stackToken; - - State state; - void setDone(State s); - uint pos; - void shift(uint p); - int lookupKeyword(const char *); - - bool isWhiteSpace() const; - bool isLineTerminator() const; - bool isHexDigit(ushort c) const; - bool isOctalDigit(ushort c) const; - - int matchPunctuator(ushort c1, ushort c2, - ushort c3, ushort c4); - ushort singleEscape(ushort c) const; - ushort convertOctal(ushort c1, ushort c2, - ushort c3) const; -public: - static unsigned char convertHex(ushort c1); - static unsigned char convertHex(ushort c1, ushort c2); - static QChar convertUnicode(ushort c1, ushort c2, - ushort c3, ushort c4); - static bool isIdentLetter(ushort c); - static bool isDecimalDigit(ushort c); - - inline int ival() const { return qsyylval.toInt(); } - inline double dval() const { return qsyylval.toDouble(); } - inline QString ustr() const { return qsyylval.toString(); } - inline QVariant val() const { return qsyylval; } - - const QChar *characterBuffer() const { return buffer16; } - int characterCount() const { return pos16; } - -private: - void record8(ushort c); - void record16(QChar c); - void recordStartPos(); - - int findReservedWord(const QChar *buffer, int size) const; - - void syncProhibitAutomaticSemicolon(); - - const QChar *code; - uint length; - int yycolumn; - int startlineno; - int startcolumn; - int bol; // begin of line - - QVariant qsyylval; - - // current and following unicode characters - ushort current, next1, next2, next3; - - struct keyword { - const char *name; - int token; - }; - - QString errmsg; - Error err; - - bool wantRx; - bool check_reserved; - - ParenthesesState parenthesesState; - int parenthesesCount; - bool prohibitAutomaticSemicolon; -}; - -} // namespace QScript - -extern double qstrtod(const char *s00, char const **se, bool *ok); - -#define shiftWindowsLineBreak() if(current == '\r' && next1 == '\n') shift(1); - -namespace QScript { - -static int toDigit(char c) -{ - if ((c >= '0') && (c <= '9')) - return c - '0'; - else if ((c >= 'a') && (c <= 'z')) - return 10 + c - 'a'; - else if ((c >= 'A') && (c <= 'Z')) - return 10 + c - 'A'; - return -1; -} - -double integerFromString(const char *buf, int size, int radix) -{ - if (size == 0) - return qSNaN(); - - double sign = 1.0; - int i = 0; - if (buf[0] == '+') { - ++i; - } else if (buf[0] == '-') { - sign = -1.0; - ++i; - } - - if (((size-i) >= 2) && (buf[i] == '0')) { - if (((buf[i+1] == 'x') || (buf[i+1] == 'X')) - && (radix < 34)) { - if ((radix != 0) && (radix != 16)) - return 0; - radix = 16; - i += 2; - } else { - if (radix == 0) { - radix = 8; - ++i; - } - } - } else if (radix == 0) { - radix = 10; - } - - int j = i; - for ( ; i < size; ++i) { - int d = toDigit(buf[i]); - if ((d == -1) || (d >= radix)) - break; - } - double result; - if (j == i) { - if (!qstrcmp(buf, "Infinity")) - result = qInf(); - else - result = qSNaN(); - } else { - result = 0; - double multiplier = 1; - for (--i ; i >= j; --i, multiplier *= radix) - result += toDigit(buf[i]) * multiplier; - } - result *= sign; - return result; -} - -} // namespace QScript - -QScript::Lexer::Lexer() - : - yylineno(0), - size8(128), size16(128), restrKeyword(false), - stackToken(-1), pos(0), - code(0), length(0), - bol(true), - current(0), next1(0), next2(0), next3(0), - err(NoError), - check_reserved(true), - parenthesesState(IgnoreParentheses), - prohibitAutomaticSemicolon(false) -{ - // allocate space for read buffers - buffer8 = new char[size8]; - buffer16 = new QChar[size16]; - flags = 0; - -} - -QScript::Lexer::~Lexer() -{ - delete [] buffer8; - delete [] buffer16; -} - -void QScript::Lexer::setCode(const QString &c, int lineno) -{ - errmsg = QString(); - yylineno = lineno; - yycolumn = 1; - restrKeyword = false; - delimited = false; - stackToken = -1; - pos = 0; - code = c.unicode(); - length = c.length(); - bol = true; - - // read first characters - current = (length > 0) ? code[0].unicode() : 0; - next1 = (length > 1) ? code[1].unicode() : 0; - next2 = (length > 2) ? code[2].unicode() : 0; - next3 = (length > 3) ? code[3].unicode() : 0; -} - -void QScript::Lexer::shift(uint p) -{ - while (p--) { - ++pos; - ++yycolumn; - current = next1; - next1 = next2; - next2 = next3; - next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0; - } -} - -void QScript::Lexer::setDone(State s) -{ - state = s; - done = true; -} - -int QScript::Lexer::findReservedWord(const QChar *c, int size) const -{ - switch (size) { - case 2: { - if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')) - return QScriptGrammar::T_DO; - else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f')) - return QScriptGrammar::T_IF; - else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')) - return QScriptGrammar::T_IN; - } break; - - case 3: { - if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r')) - return QScriptGrammar::T_FOR; - else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w')) - return QScriptGrammar::T_NEW; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y')) - return QScriptGrammar::T_TRY; - else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r')) - return QScriptGrammar::T_VAR; - else if (check_reserved) { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 4: { - if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_CASE; - else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_ELSE; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s')) - return QScriptGrammar::T_THIS; - else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d')) - return QScriptGrammar::T_VOID; - else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h')) - return QScriptGrammar::T_WITH; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_TRUE; - else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l')) - return QScriptGrammar::T_NULL; - else if (check_reserved) { - if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n') - && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 5: { - if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('k')) - return QScriptGrammar::T_BREAK; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c') - && c[4] == QLatin1Char('h')) - return QScriptGrammar::T_CATCH; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('w')) - return QScriptGrammar::T_THROW; - else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('e')) - return QScriptGrammar::T_WHILE; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s') - && c[4] == QLatin1Char('t')) - return QScriptGrammar::T_CONST; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s') - && c[4] == QLatin1Char('e')) - return QScriptGrammar::T_FALSE; - else if (check_reserved) { - if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r') - && c[4] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('r')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('l')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s') - && c[4] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 6: { - if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e')) - return QScriptGrammar::T_DELETE; - else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n')) - return QScriptGrammar::T_RETURN; - else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h')) - return QScriptGrammar::T_SWITCH; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f')) - return QScriptGrammar::T_TYPEOF; - else if (check_reserved) { - if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b') - && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i') - && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') - && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') - && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 7: { - if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l') - && c[6] == QLatin1Char('t')) - return QScriptGrammar::T_DEFAULT; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l') - && c[6] == QLatin1Char('y')) - return QScriptGrammar::T_FINALLY; - else if (check_reserved) { - if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a') - && c[6] == QLatin1Char('n')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d') - && c[6] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a') - && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k') - && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g') - && c[6] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v') - && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t') - && c[6] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 8: { - if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n') - && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e')) - return QScriptGrammar::T_CONTINUE; - else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') - && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') - && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')) - return QScriptGrammar::T_FUNCTION; - else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') - && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u') - && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g') - && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r')) - return QScriptGrammar::T_DEBUGGER; - else if (check_reserved) { - if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a') - && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') - && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a') - && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') - && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 9: { - if (check_reserved) { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') - && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') - && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f') - && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c') - && c[8] == QLatin1Char('e')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n') - && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i') - && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') - && c[8] == QLatin1Char('t')) - return QScriptGrammar::T_RESERVED_WORD; - else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') - && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c') - && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e') - && c[8] == QLatin1Char('d')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 10: { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') - && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') - && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n') - && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e') - && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f')) - return QScriptGrammar::T_INSTANCEOF; - else if (check_reserved) { - if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') - && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l') - && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m') - && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') - && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - case 12: { - if (check_reserved) { - if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y') - && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') - && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r') - && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n') - && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z') - && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d')) - return QScriptGrammar::T_RESERVED_WORD; - } - } break; - - } // switch - - return -1; -} - -int QScript::Lexer::lex() -{ - int token = 0; - state = Start; - ushort stringType = 0; // either single or double quotes - pos8 = pos16 = 0; - done = false; - terminator = false; - - // did we push a token on the stack previously ? - // (after an automatic semicolon insertion) - if (stackToken >= 0) { - setDone(Other); - token = stackToken; - stackToken = -1; - } - - while (!done) { - switch (state) { - case Start: - if (isWhiteSpace()) { - // do nothing - } else if (current == '/' && next1 == '/') { - recordStartPos(); - shift(1); - state = InSingleLineComment; - } else if (current == '/' && next1 == '*') { - recordStartPos(); - shift(1); - state = InMultiLineComment; - } else if (current == 0) { - syncProhibitAutomaticSemicolon(); - if (!terminator && !delimited && !prohibitAutomaticSemicolon) { - // automatic semicolon insertion if program incomplete - token = QScriptGrammar::T_SEMICOLON; - stackToken = 0; - setDone(Other); - } else { - setDone(Eof); - } - } else if (isLineTerminator()) { - shiftWindowsLineBreak(); - yylineno++; - yycolumn = 0; - bol = true; - terminator = true; - syncProhibitAutomaticSemicolon(); - if (restrKeyword) { - token = QScriptGrammar::T_SEMICOLON; - setDone(Other); - } - } else if (current == '"' || current == '\'') { - recordStartPos(); - state = InString; - stringType = current; - } else if (isIdentLetter(current)) { - recordStartPos(); - record16(current); - state = InIdentifier; - } else if (current == '0') { - recordStartPos(); - record8(current); - state = InNum0; - } else if (isDecimalDigit(current)) { - recordStartPos(); - record8(current); - state = InNum; - } else if (current == '.' && isDecimalDigit(next1)) { - recordStartPos(); - record8(current); - state = InDecimal; - } else { - recordStartPos(); - token = matchPunctuator(current, next1, next2, next3); - if (token != -1) { - if (terminator && !delimited && !prohibitAutomaticSemicolon - && (token == QScriptGrammar::T_PLUS_PLUS - || token == QScriptGrammar::T_MINUS_MINUS)) { - // automatic semicolon insertion - stackToken = token; - token = QScriptGrammar::T_SEMICOLON; - } - setDone(Other); - } - else { - setDone(Bad); - err = IllegalCharacter; - errmsg = QLatin1String("Illegal character"); - } - } - break; - case InString: - if (current == stringType) { - shift(1); - setDone(String); - } else if (current == 0 || isLineTerminator()) { - setDone(Bad); - err = UnclosedStringLiteral; - errmsg = QLatin1String("Unclosed string at end of line"); - } else if (current == '\\') { - state = InEscapeSequence; - } else { - record16(current); - } - break; - // Escape Sequences inside of strings - case InEscapeSequence: - if (isOctalDigit(current)) { - if (current >= '0' && current <= '3' && - isOctalDigit(next1) && isOctalDigit(next2)) { - record16(convertOctal(current, next1, next2)); - shift(2); - state = InString; - } else if (isOctalDigit(current) && - isOctalDigit(next1)) { - record16(convertOctal('0', current, next1)); - shift(1); - state = InString; - } else if (isOctalDigit(current)) { - record16(convertOctal('0', '0', current)); - state = InString; - } else { - setDone(Bad); - err = IllegalEscapeSequence; - errmsg = QLatin1String("Illegal escape squence"); - } - } else if (current == 'x') - state = InHexEscape; - else if (current == 'u') - state = InUnicodeEscape; - else { - record16(singleEscape(current)); - state = InString; - } - break; - case InHexEscape: - if (isHexDigit(current) && isHexDigit(next1)) { - state = InString; - record16(QLatin1Char(convertHex(current, next1))); - shift(1); - } else if (current == stringType) { - record16(QLatin1Char('x')); - shift(1); - setDone(String); - } else { - record16(QLatin1Char('x')); - record16(current); - state = InString; - } - break; - case InUnicodeEscape: - if (isHexDigit(current) && isHexDigit(next1) && - isHexDigit(next2) && isHexDigit(next3)) { - record16(convertUnicode(current, next1, next2, next3)); - shift(3); - state = InString; - } else if (current == stringType) { - record16(QLatin1Char('u')); - shift(1); - setDone(String); - } else { - setDone(Bad); - err = IllegalUnicodeEscapeSequence; - errmsg = QLatin1String("Illegal unicode escape sequence"); - } - break; - case InSingleLineComment: - if (isLineTerminator()) { - shiftWindowsLineBreak(); - yylineno++; - yycolumn = 0; - terminator = true; - bol = true; - if (restrKeyword) { - token = QScriptGrammar::T_SEMICOLON; - setDone(Other); - } else - state = Start; - } else if (current == 0) { - setDone(Eof); - } - break; - case InMultiLineComment: - if (current == 0) { - setDone(Bad); - err = UnclosedComment; - errmsg = QLatin1String("Unclosed comment at end of file"); - } else if (isLineTerminator()) { - shiftWindowsLineBreak(); - yylineno++; - } else if (current == '*' && next1 == '/') { - state = Start; - shift(1); - } - break; - case InIdentifier: - if (isIdentLetter(current) || isDecimalDigit(current)) { - record16(current); - break; - } - setDone(Identifier); - break; - case InNum0: - if (current == 'x' || current == 'X') { - record8(current); - state = InHex; - } else if (current == '.') { - record8(current); - state = InDecimal; - } else if (current == 'e' || current == 'E') { - record8(current); - state = InExponentIndicator; - } else if (isOctalDigit(current)) { - record8(current); - state = InOctal; - } else if (isDecimalDigit(current)) { - record8(current); - state = InDecimal; - } else { - setDone(Number); - } - break; - case InHex: - if (isHexDigit(current)) - record8(current); - else - setDone(Hex); - break; - case InOctal: - if (isOctalDigit(current)) { - record8(current); - } else if (isDecimalDigit(current)) { - record8(current); - state = InDecimal; - } else { - setDone(Octal); - } - break; - case InNum: - if (isDecimalDigit(current)) { - record8(current); - } else if (current == '.') { - record8(current); - state = InDecimal; - } else if (current == 'e' || current == 'E') { - record8(current); - state = InExponentIndicator; - } else { - setDone(Number); - } - break; - case InDecimal: - if (isDecimalDigit(current)) { - record8(current); - } else if (current == 'e' || current == 'E') { - record8(current); - state = InExponentIndicator; - } else { - setDone(Number); - } - break; - case InExponentIndicator: - if (current == '+' || current == '-') { - record8(current); - } else if (isDecimalDigit(current)) { - record8(current); - state = InExponent; - } else { - setDone(Bad); - err = IllegalExponentIndicator; - errmsg = QLatin1String("Illegal syntax for exponential number"); - } - break; - case InExponent: - if (isDecimalDigit(current)) { - record8(current); - } else { - setDone(Number); - } - break; - default: - Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement"); - } - - // move on to the next character - if (!done) - shift(1); - if (state != Start && state != InSingleLineComment) - bol = false; - } - - // no identifiers allowed directly after numeric literal, e.g. "3in" is bad - if ((state == Number || state == Octal || state == Hex) - && isIdentLetter(current)) { - state = Bad; - err = IllegalIdentifier; - errmsg = QLatin1String("Identifier cannot start with numeric literal"); - } - - // terminate string - buffer8[pos8] = '\0'; - - double dval = 0; - if (state == Number) { - dval = qstrtod(buffer8, 0, 0); - } else if (state == Hex) { // scan hex numbers - dval = QScript::integerFromString(buffer8, pos8, 16); - state = Number; - } else if (state == Octal) { // scan octal number - dval = QScript::integerFromString(buffer8, pos8, 8); - state = Number; - } - - restrKeyword = false; - delimited = false; - - switch (parenthesesState) { - case IgnoreParentheses: - break; - case CountParentheses: - if (token == QScriptGrammar::T_RPAREN) { - --parenthesesCount; - if (parenthesesCount == 0) - parenthesesState = BalancedParentheses; - } else if (token == QScriptGrammar::T_LPAREN) { - ++parenthesesCount; - } - break; - case BalancedParentheses: - parenthesesState = IgnoreParentheses; - break; - } - - switch (state) { - case Eof: - return 0; - case Other: - if(token == QScriptGrammar::T_RBRACE || token == QScriptGrammar::T_SEMICOLON) - delimited = true; - return token; - case Identifier: - if ((token = findReservedWord(buffer16, pos16)) < 0) { - /* TODO: close leak on parse error. same holds true for String */ - qsyylval = QString(buffer16, pos16); - return QScriptGrammar::T_IDENTIFIER; - } - if (token == QScriptGrammar::T_CONTINUE || token == QScriptGrammar::T_BREAK - || token == QScriptGrammar::T_RETURN || token == QScriptGrammar::T_THROW) { - restrKeyword = true; - } else if (token == QScriptGrammar::T_IF || token == QScriptGrammar::T_FOR - || token == QScriptGrammar::T_WHILE || token == QScriptGrammar::T_WITH) { - parenthesesState = CountParentheses; - parenthesesCount = 0; - } else if (token == QScriptGrammar::T_DO) { - parenthesesState = BalancedParentheses; - } - return token; - case String: - qsyylval = QString(buffer16, pos16); - return QScriptGrammar::T_STRING_LITERAL; - case Number: - qsyylval = dval; - return QScriptGrammar::T_NUMERIC_LITERAL; - case Bad: - return -1; - default: - Q_ASSERT(!"unhandled numeration value in switch"); - return -1; - } -} - -bool QScript::Lexer::isWhiteSpace() const -{ - return (current == ' ' || current == '\t' || - current == 0x0b || current == 0x0c); -} - -bool QScript::Lexer::isLineTerminator() const -{ - return (current == '\n' || current == '\r'); -} - -bool QScript::Lexer::isIdentLetter(ushort c) -{ - /* TODO: allow other legitimate unicode chars */ - return ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == '$' - || c == '_'); -} - -bool QScript::Lexer::isDecimalDigit(ushort c) -{ - return (c >= '0' && c <= '9'); -} - -bool QScript::Lexer::isHexDigit(ushort c) const -{ - return ((c >= '0' && c <= '9') - || (c >= 'a' && c <= 'f') - || (c >= 'A' && c <= 'F')); -} - -bool QScript::Lexer::isOctalDigit(ushort c) const -{ - return (c >= '0' && c <= '7'); -} - -int QScript::Lexer::matchPunctuator(ushort c1, ushort c2, - ushort c3, ushort c4) -{ - if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { - shift(4); - return QScriptGrammar::T_GT_GT_GT_EQ; - } else if (c1 == '=' && c2 == '=' && c3 == '=') { - shift(3); - return QScriptGrammar::T_EQ_EQ_EQ; - } else if (c1 == '!' && c2 == '=' && c3 == '=') { - shift(3); - return QScriptGrammar::T_NOT_EQ_EQ; - } else if (c1 == '>' && c2 == '>' && c3 == '>') { - shift(3); - return QScriptGrammar::T_GT_GT_GT; - } else if (c1 == '<' && c2 == '<' && c3 == '=') { - shift(3); - return QScriptGrammar::T_LT_LT_EQ; - } else if (c1 == '>' && c2 == '>' && c3 == '=') { - shift(3); - return QScriptGrammar::T_GT_GT_EQ; - } else if (c1 == '<' && c2 == '=') { - shift(2); - return QScriptGrammar::T_LE; - } else if (c1 == '>' && c2 == '=') { - shift(2); - return QScriptGrammar::T_GE; - } else if (c1 == '!' && c2 == '=') { - shift(2); - return QScriptGrammar::T_NOT_EQ; - } else if (c1 == '+' && c2 == '+') { - shift(2); - return QScriptGrammar::T_PLUS_PLUS; - } else if (c1 == '-' && c2 == '-') { - shift(2); - return QScriptGrammar::T_MINUS_MINUS; - } else if (c1 == '=' && c2 == '=') { - shift(2); - return QScriptGrammar::T_EQ_EQ; - } else if (c1 == '+' && c2 == '=') { - shift(2); - return QScriptGrammar::T_PLUS_EQ; - } else if (c1 == '-' && c2 == '=') { - shift(2); - return QScriptGrammar::T_MINUS_EQ; - } else if (c1 == '*' && c2 == '=') { - shift(2); - return QScriptGrammar::T_STAR_EQ; - } else if (c1 == '/' && c2 == '=') { - shift(2); - return QScriptGrammar::T_DIVIDE_EQ; - } else if (c1 == '&' && c2 == '=') { - shift(2); - return QScriptGrammar::T_AND_EQ; - } else if (c1 == '^' && c2 == '=') { - shift(2); - return QScriptGrammar::T_XOR_EQ; - } else if (c1 == '%' && c2 == '=') { - shift(2); - return QScriptGrammar::T_REMAINDER_EQ; - } else if (c1 == '|' && c2 == '=') { - shift(2); - return QScriptGrammar::T_OR_EQ; - } else if (c1 == '<' && c2 == '<') { - shift(2); - return QScriptGrammar::T_LT_LT; - } else if (c1 == '>' && c2 == '>') { - shift(2); - return QScriptGrammar::T_GT_GT; - } else if (c1 == '&' && c2 == '&') { - shift(2); - return QScriptGrammar::T_AND_AND; - } else if (c1 == '|' && c2 == '|') { - shift(2); - return QScriptGrammar::T_OR_OR; - } - - switch(c1) { - case '=': shift(1); return QScriptGrammar::T_EQ; - case '>': shift(1); return QScriptGrammar::T_GT; - case '<': shift(1); return QScriptGrammar::T_LT; - case ',': shift(1); return QScriptGrammar::T_COMMA; - case '!': shift(1); return QScriptGrammar::T_NOT; - case '~': shift(1); return QScriptGrammar::T_TILDE; - case '?': shift(1); return QScriptGrammar::T_QUESTION; - case ':': shift(1); return QScriptGrammar::T_COLON; - case '.': shift(1); return QScriptGrammar::T_DOT; - case '+': shift(1); return QScriptGrammar::T_PLUS; - case '-': shift(1); return QScriptGrammar::T_MINUS; - case '*': shift(1); return QScriptGrammar::T_STAR; - case '/': shift(1); return QScriptGrammar::T_DIVIDE_; - case '&': shift(1); return QScriptGrammar::T_AND; - case '|': shift(1); return QScriptGrammar::T_OR; - case '^': shift(1); return QScriptGrammar::T_XOR; - case '%': shift(1); return QScriptGrammar::T_REMAINDER; - case '(': shift(1); return QScriptGrammar::T_LPAREN; - case ')': shift(1); return QScriptGrammar::T_RPAREN; - case '{': shift(1); return QScriptGrammar::T_LBRACE; - case '}': shift(1); return QScriptGrammar::T_RBRACE; - case '[': shift(1); return QScriptGrammar::T_LBRACKET; - case ']': shift(1); return QScriptGrammar::T_RBRACKET; - case ';': shift(1); return QScriptGrammar::T_SEMICOLON; - - default: return -1; - } -} - -ushort QScript::Lexer::singleEscape(ushort c) const -{ - switch(c) { - case 'b': - return 0x08; - case 't': - return 0x09; - case 'n': - return 0x0A; - case 'v': - return 0x0B; - case 'f': - return 0x0C; - case 'r': - return 0x0D; - case '"': - return 0x22; - case '\'': - return 0x27; - case '\\': - return 0x5C; - default: - return c; - } -} - -ushort QScript::Lexer::convertOctal(ushort c1, ushort c2, - ushort c3) const -{ - return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); -} - -unsigned char QScript::Lexer::convertHex(ushort c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - else if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - else - return (c - 'A' + 10); -} - -unsigned char QScript::Lexer::convertHex(ushort c1, ushort c2) -{ - return ((convertHex(c1) << 4) + convertHex(c2)); -} - -QChar QScript::Lexer::convertUnicode(ushort c1, ushort c2, - ushort c3, ushort c4) -{ - return QChar((convertHex(c3) << 4) + convertHex(c4), - (convertHex(c1) << 4) + convertHex(c2)); -} - -void QScript::Lexer::record8(ushort c) -{ - Q_ASSERT(c <= 0xff); - - // enlarge buffer if full - if (pos8 >= size8 - 1) { - char *tmp = new char[2 * size8]; - memcpy(tmp, buffer8, size8 * sizeof(char)); - delete [] buffer8; - buffer8 = tmp; - size8 *= 2; - } - - buffer8[pos8++] = (char) c; -} - -void QScript::Lexer::record16(QChar c) -{ - // enlarge buffer if full - if (pos16 >= size16 - 1) { - QChar *tmp = new QChar[2 * size16]; - memcpy(tmp, buffer16, size16 * sizeof(QChar)); - delete [] buffer16; - buffer16 = tmp; - size16 *= 2; - } - - buffer16[pos16++] = c; -} - -void QScript::Lexer::recordStartPos() -{ - startlineno = yylineno; - startcolumn = yycolumn; -} - -bool QScript::Lexer::scanRegExp(RegExpBodyPrefix prefix) -{ - pos16 = 0; - bool lastWasEscape = false; - - if (prefix == EqualPrefix) - record16(QLatin1Char('=')); - - while (1) { - if (isLineTerminator() || current == 0) { - errmsg = QLatin1String("Unterminated regular expression literal"); - return false; - } - else if (current != '/' || lastWasEscape == true) - { - record16(current); - lastWasEscape = !lastWasEscape && (current == '\\'); - } - else { - pattern = QString(buffer16, pos16); - pos16 = 0; - shift(1); - break; - } - shift(1); - } - - flags = 0; - while (isIdentLetter(current)) { - record16(current); - shift(1); - } - - return true; -} - -void QScript::Lexer::syncProhibitAutomaticSemicolon() -{ - if (parenthesesState == BalancedParentheses) { - // we have seen something like "if (foo)", which means we should - // never insert an automatic semicolon at this point, since it would - // then be expanded into an empty statement (ECMA-262 7.9.1) - prohibitAutomaticSemicolon = true; - parenthesesState = IgnoreParentheses; - } else { - prohibitAutomaticSemicolon = false; - } -} - - -class Translator; - -class QScriptParser: protected $table -{ -public: - QVariant val; - - struct Location { - int startLine; - int startColumn; - int endLine; - int endColumn; - }; - -public: - QScriptParser(); - ~QScriptParser(); - - bool parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator); - - inline QString errorMessage() const - { return error_message; } - inline int errorLineNumber() const - { return error_lineno; } - inline int errorColumnNumber() const - { return error_column; } - -protected: - inline void reallocateStack(); - - inline QVariant &sym(int index) - { return sym_stack [tos + index - 1]; } - - inline Location &loc(int index) - { return location_stack [tos + index - 2]; } - -protected: - int tos; - int stack_size; - QVector<QVariant> sym_stack; - int *state_stack; - Location *location_stack; - QString error_message; - int error_lineno; - int error_column; -}; - -inline void QScriptParser::reallocateStack() -{ - if (! stack_size) - stack_size = 128; - else - stack_size <<= 1; - - sym_stack.resize(stack_size); - state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); - location_stack = reinterpret_cast<Location*> (qRealloc(location_stack, stack_size * sizeof(Location))); -} - -inline static bool automatic(QScript::Lexer *lexer, int token) -{ - return (token == $table::T_RBRACE) - || (token == 0) - || lexer->prevTerminator(); -} - -QScriptParser::QScriptParser(): - tos(0), - stack_size(0), - sym_stack(0), - state_stack(0), - location_stack(0) -{ -} - -QScriptParser::~QScriptParser() -{ - if (stack_size) { - qFree(state_stack); - qFree(location_stack); - } -} - -static inline QScriptParser::Location location(QScript::Lexer *lexer) -{ - QScriptParser::Location loc; - loc.startLine = lexer->startLineNo(); - loc.startColumn = lexer->startColumnNo(); - loc.endLine = lexer->endLineNo(); - loc.endColumn = lexer->endColumnNo(); - return loc; -} - -bool QScriptParser::parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator) -{ - const int INITIAL_STATE = 0; - - int yytoken = -1; - int saved_yytoken = -1; - int identLineNo = -1; - - reallocateStack(); - - tos = 0; - state_stack[++tos] = INITIAL_STATE; - - while (true) - { - const int state = state_stack [tos]; - if (yytoken == -1 && - TERMINAL_COUNT != action_index [state]) - { - if (saved_yytoken == -1) - { - yytoken = lexer->lex(); - location_stack [tos] = location(lexer); - } - else - { - yytoken = saved_yytoken; - saved_yytoken = -1; - } - } - - int act = t_action (state, yytoken); - - if (act == ACCEPT_STATE) - return true; - - else if (act > 0) - { - if (++tos == stack_size) - reallocateStack(); - - sym_stack [tos] = lexer->val (); - state_stack [tos] = act; - location_stack [tos] = location(lexer); - yytoken = -1; - } - - else if (act < 0) - { - int r = - act - 1; - - tos -= rhs [r]; - act = state_stack [tos++]; - - switch (r) { -./ - -PrimaryExpression: T_THIS ; - -PrimaryExpression: T_IDENTIFIER ; -/. -case $rule_number: { - sym(1) = sym(1).toByteArray(); - identLineNo = lexer->startLineNo(); -} break; -./ - -PrimaryExpression: T_NULL ; -PrimaryExpression: T_TRUE ; -PrimaryExpression: T_FALSE ; -PrimaryExpression: T_NUMERIC_LITERAL ; -PrimaryExpression: T_STRING_LITERAL ; - -PrimaryExpression: T_DIVIDE_ ; -/: -#define Q_SCRIPT_REGEXPLITERAL_RULE1 $rule_number -:/ -/. -case $rule_number: { - bool rx = lexer->scanRegExp(QScript::Lexer::NoPrefix); - if (!rx) { - error_message = lexer->errorMessage(); - error_lineno = lexer->startLineNo(); - error_column = lexer->startColumnNo(); - return false; - } -} break; -./ - -PrimaryExpression: T_DIVIDE_EQ ; -/: -#define Q_SCRIPT_REGEXPLITERAL_RULE2 $rule_number -:/ -/. -case $rule_number: { - bool rx = lexer->scanRegExp(QScript::Lexer::EqualPrefix); - if (!rx) { - error_message = lexer->errorMessage(); - error_lineno = lexer->startLineNo(); - error_column = lexer->startColumnNo(); - return false; - } -} break; -./ - -PrimaryExpression: T_LBRACKET ElisionOpt T_RBRACKET ; -PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ; -PrimaryExpression: T_LBRACKET ElementList T_COMMA ElisionOpt T_RBRACKET ; -PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ; -PrimaryExpression: T_LPAREN Expression T_RPAREN ; -ElementList: ElisionOpt AssignmentExpression ; -ElementList: ElementList T_COMMA ElisionOpt AssignmentExpression ; -Elision: T_COMMA ; -Elision: Elision T_COMMA ; -ElisionOpt: ; -ElisionOpt: Elision ; -PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ; -PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ; -PropertyName: T_IDENTIFIER ; -PropertyName: T_STRING_LITERAL ; -PropertyName: T_NUMERIC_LITERAL ; -PropertyName: ReservedIdentifier ; -ReservedIdentifier: T_BREAK ; -ReservedIdentifier: T_CASE ; -ReservedIdentifier: T_CATCH ; -ReservedIdentifier: T_CONST ; -ReservedIdentifier: T_CONTINUE ; -ReservedIdentifier: T_DEBUGGER ; -ReservedIdentifier: T_DEFAULT ; -ReservedIdentifier: T_DELETE ; -ReservedIdentifier: T_DO ; -ReservedIdentifier: T_ELSE ; -ReservedIdentifier: T_FALSE ; -ReservedIdentifier: T_FINALLY ; -ReservedIdentifier: T_FOR ; -ReservedIdentifier: T_FUNCTION ; -ReservedIdentifier: T_IF ; -ReservedIdentifier: T_IN ; -ReservedIdentifier: T_INSTANCEOF ; -ReservedIdentifier: T_NEW ; -ReservedIdentifier: T_NULL ; -ReservedIdentifier: T_RESERVED_WORD ; -ReservedIdentifier: T_RETURN ; -ReservedIdentifier: T_SWITCH ; -ReservedIdentifier: T_THIS ; -ReservedIdentifier: T_THROW ; -ReservedIdentifier: T_TRUE ; -ReservedIdentifier: T_TRY ; -ReservedIdentifier: T_TYPEOF ; -ReservedIdentifier: T_VAR ; -ReservedIdentifier: T_VOID ; -ReservedIdentifier: T_WHILE ; -ReservedIdentifier: T_WITH ; -PropertyIdentifier: T_IDENTIFIER ; -PropertyIdentifier: ReservedIdentifier ; - -MemberExpression: PrimaryExpression ; -MemberExpression: FunctionExpression ; -MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ; -MemberExpression: MemberExpression T_DOT PropertyIdentifier ; -MemberExpression: T_NEW MemberExpression Arguments ; -NewExpression: MemberExpression ; -NewExpression: T_NEW NewExpression ; - -CallExpression: MemberExpression Arguments ; -/. -case $rule_number: { - QString name = sym(1).toString(); - if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) { - QVariantList args = sym(2).toList(); - if (args.size() < 2) { - qWarning("%s:%d: %s() requires at least two arguments", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - if ((args.at(0).type() != QVariant::String) - || (args.at(1).type() != QVariant::String)) { - qWarning("%s:%d: %s(): both arguments must be literal strings", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - QString context = args.at(0).toString(); - QString text = args.at(1).toString(); - QString comment = args.value(2).toString(); - QString extracomment; - bool plural = (args.size() > 4); - recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); - } - } - } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) { - QVariantList args = sym(2).toList(); - if (args.size() < 1) { - qWarning("%s:%d: %s() requires at least one argument", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - if (args.at(0).type() != QVariant::String) { - qWarning("%s:%d: %s(): text to translate must be a literal string", - qPrintable(fileName), identLineNo, qPrintable(name)); - } else { - QString context = QFileInfo(fileName).baseName(); - QString text = args.at(0).toString(); - QString comment = args.value(1).toString(); - QString extracomment; - bool plural = (args.size() > 2); - recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); - } - } - } -} break; -./ - -CallExpression: CallExpression Arguments ; -CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ; -CallExpression: CallExpression T_DOT PropertyIdentifier ; - -Arguments: T_LPAREN T_RPAREN ; -/. -case $rule_number: { - sym(1) = QVariantList(); -} break; -./ - -Arguments: T_LPAREN ArgumentList T_RPAREN ; -/. -case $rule_number: { - sym(1) = sym(2); -} break; -./ - -ArgumentList: AssignmentExpression ; -/. -case $rule_number: { - sym(1) = QVariantList() << sym(1); -} break; -./ - -ArgumentList: ArgumentList T_COMMA AssignmentExpression ; -/. -case $rule_number: { - sym(1) = sym(1).toList() << sym(3); -} break; -./ - -LeftHandSideExpression: NewExpression ; -LeftHandSideExpression: CallExpression ; -PostfixExpression: LeftHandSideExpression ; -PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ; -PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ; -UnaryExpression: PostfixExpression ; -UnaryExpression: T_DELETE UnaryExpression ; -UnaryExpression: T_VOID UnaryExpression ; -UnaryExpression: T_TYPEOF UnaryExpression ; -UnaryExpression: T_PLUS_PLUS UnaryExpression ; -UnaryExpression: T_MINUS_MINUS UnaryExpression ; -UnaryExpression: T_PLUS UnaryExpression ; -UnaryExpression: T_MINUS UnaryExpression ; -UnaryExpression: T_TILDE UnaryExpression ; -UnaryExpression: T_NOT UnaryExpression ; -MultiplicativeExpression: UnaryExpression ; -MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ; -MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ; -MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ; -AdditiveExpression: MultiplicativeExpression ; - -AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ; -/. -case $rule_number: { - if ((sym(1).type() == QVariant::String) || (sym(3).type() == QVariant::String)) - sym(1) = sym(1).toString() + sym(3).toString(); - else - sym(1) = QVariant(); -} break; -./ - -AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ; -ShiftExpression: AdditiveExpression ; -ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ; -ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ; -ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ; -RelationalExpression: ShiftExpression ; -RelationalExpression: RelationalExpression T_LT ShiftExpression ; -RelationalExpression: RelationalExpression T_GT ShiftExpression ; -RelationalExpression: RelationalExpression T_LE ShiftExpression ; -RelationalExpression: RelationalExpression T_GE ShiftExpression ; -RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ; -RelationalExpression: RelationalExpression T_IN ShiftExpression ; -RelationalExpressionNotIn: ShiftExpression ; -RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ; -RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ; -RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ; -RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ; -RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ; -EqualityExpression: RelationalExpression ; -EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ; -EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ; -EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ; -EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ; -EqualityExpressionNotIn: RelationalExpressionNotIn ; -EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ; -EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn; -EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ; -EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ; -BitwiseANDExpression: EqualityExpression ; -BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ; -BitwiseANDExpressionNotIn: EqualityExpressionNotIn ; -BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ; -BitwiseXORExpression: BitwiseANDExpression ; -BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ; -BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ; -BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ; -BitwiseORExpression: BitwiseXORExpression ; -BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ; -BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ; -BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ; -LogicalANDExpression: BitwiseORExpression ; -LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ; -LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ; -LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ; -LogicalORExpression: LogicalANDExpression ; -LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ; -LogicalORExpressionNotIn: LogicalANDExpressionNotIn ; -LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ; -ConditionalExpression: LogicalORExpression ; -ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ; -ConditionalExpressionNotIn: LogicalORExpressionNotIn ; -ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ; -AssignmentExpression: ConditionalExpression ; -AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ; -AssignmentExpressionNotIn: ConditionalExpressionNotIn ; -AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ; -AssignmentOperator: T_EQ ; -AssignmentOperator: T_STAR_EQ ; -AssignmentOperator: T_DIVIDE_EQ ; -AssignmentOperator: T_REMAINDER_EQ ; -AssignmentOperator: T_PLUS_EQ ; -AssignmentOperator: T_MINUS_EQ ; -AssignmentOperator: T_LT_LT_EQ ; -AssignmentOperator: T_GT_GT_EQ ; -AssignmentOperator: T_GT_GT_GT_EQ ; -AssignmentOperator: T_AND_EQ ; -AssignmentOperator: T_XOR_EQ ; -AssignmentOperator: T_OR_EQ ; -Expression: AssignmentExpression ; -Expression: Expression T_COMMA AssignmentExpression ; -ExpressionOpt: ; -ExpressionOpt: Expression ; -ExpressionNotIn: AssignmentExpressionNotIn ; -ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ; -ExpressionNotInOpt: ; -ExpressionNotInOpt: ExpressionNotIn ; - -Statement: Block ; -Statement: VariableStatement ; -Statement: EmptyStatement ; -Statement: ExpressionStatement ; -Statement: IfStatement ; -Statement: IterationStatement ; -Statement: ContinueStatement ; -Statement: BreakStatement ; -Statement: ReturnStatement ; -Statement: WithStatement ; -Statement: LabelledStatement ; -Statement: SwitchStatement ; -Statement: ThrowStatement ; -Statement: TryStatement ; -Statement: DebuggerStatement ; - -Block: T_LBRACE StatementListOpt T_RBRACE ; -StatementList: Statement ; -StatementList: StatementList Statement ; -StatementListOpt: ; -StatementListOpt: StatementList ; -VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ; -VariableDeclarationKind: T_CONST ; -VariableDeclarationKind: T_VAR ; -VariableDeclarationList: VariableDeclaration ; -VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ; -VariableDeclarationListNotIn: VariableDeclarationNotIn ; -VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ; -VariableDeclaration: T_IDENTIFIER InitialiserOpt ; -VariableDeclarationNotIn: T_IDENTIFIER InitialiserNotInOpt ; -Initialiser: T_EQ AssignmentExpression ; -InitialiserOpt: ; -InitialiserOpt: Initialiser ; -InitialiserNotIn: T_EQ AssignmentExpressionNotIn ; -InitialiserNotInOpt: ; -InitialiserNotInOpt: InitialiserNotIn ; -EmptyStatement: T_SEMICOLON ; -ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -ExpressionStatement: Expression T_SEMICOLON ; -IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ; -IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ; -IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ; -IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ; -IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; -IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; -IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ; -IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ; -ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -ContinueStatement: T_CONTINUE T_SEMICOLON ; -ContinueStatement: T_CONTINUE T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -ContinueStatement: T_CONTINUE T_IDENTIFIER T_SEMICOLON ; -BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -BreakStatement: T_BREAK T_SEMICOLON ; -BreakStatement: T_BREAK T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -BreakStatement: T_BREAK T_IDENTIFIER T_SEMICOLON ; -ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ; -WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ; -SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ; -CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ; -CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ; -CaseClauses: CaseClause ; -CaseClauses: CaseClauses CaseClause ; -CaseClausesOpt: ; -CaseClausesOpt: CaseClauses ; -CaseClause: T_CASE Expression T_COLON StatementListOpt ; -DefaultClause: T_DEFAULT T_COLON StatementListOpt ; -LabelledStatement: T_IDENTIFIER T_COLON Statement ; -ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon -ThrowStatement: T_THROW Expression T_SEMICOLON ; -TryStatement: T_TRY Block Catch ; -TryStatement: T_TRY Block Finally ; -TryStatement: T_TRY Block Catch Finally ; -Catch: T_CATCH T_LPAREN T_IDENTIFIER T_RPAREN Block ; -Finally: T_FINALLY Block ; -DebuggerStatement: T_DEBUGGER ; -FunctionDeclaration: T_FUNCTION T_IDENTIFIER T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; -FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; -FormalParameterList: T_IDENTIFIER ; -FormalParameterList: FormalParameterList T_COMMA T_IDENTIFIER ; -FormalParameterListOpt: ; -FormalParameterListOpt: FormalParameterList ; -FunctionBodyOpt: ; -FunctionBodyOpt: FunctionBody ; -FunctionBody: SourceElements ; -Program: SourceElements ; -SourceElements: SourceElement ; -SourceElements: SourceElements SourceElement ; -SourceElement: Statement ; -SourceElement: FunctionDeclaration ; -IdentifierOpt: ; -IdentifierOpt: T_IDENTIFIER ; -PropertyNameAndValueListOpt: ; -PropertyNameAndValueListOpt: PropertyNameAndValueList ; - -/. - } // switch - - state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); - - if (rhs[r] > 1) { - location_stack[tos - 1].endLine = location_stack[tos + rhs[r] - 2].endLine; - location_stack[tos - 1].endColumn = location_stack[tos + rhs[r] - 2].endColumn; - location_stack[tos] = location_stack[tos + rhs[r] - 1]; - } - } - - else - { - if (saved_yytoken == -1 && automatic (lexer, yytoken) && t_action (state, T_AUTOMATIC_SEMICOLON) > 0) - { - saved_yytoken = yytoken; - yytoken = T_SEMICOLON; - continue; - } - - else if ((state == INITIAL_STATE) && (yytoken == 0)) { - // accept empty input - yytoken = T_SEMICOLON; - continue; - } - - int ers = state; - int shifts = 0; - int reduces = 0; - int expected_tokens [3]; - for (int tk = 0; tk < TERMINAL_COUNT; ++tk) - { - int k = t_action (ers, tk); - - if (! k) - continue; - else if (k < 0) - ++reduces; - else if (spell [tk]) - { - if (shifts < 3) - expected_tokens [shifts] = tk; - ++shifts; - } - } - - error_message.clear (); - if (shifts && shifts < 3) - { - bool first = true; - - for (int s = 0; s < shifts; ++s) - { - if (first) - error_message += QLatin1String ("Expected "); - else - error_message += QLatin1String (", "); - - first = false; - error_message += QLatin1String("`"); - error_message += QLatin1String (spell [expected_tokens [s]]); - error_message += QLatin1String("'"); - } - } - - if (error_message.isEmpty()) - error_message = lexer->errorMessage(); - - error_lineno = lexer->startLineNo(); - error_column = lexer->startColumnNo(); - - return false; - } - } - - return false; -} - - -bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) -{ - QTextStream ts(&dev); - QByteArray codecName; - if (!cd.m_codecForSource.isEmpty()) - codecName = cd.m_codecForSource; - else - codecName = translator.codecName(); // Just because it should be latin1 already - ts.setCodec(QTextCodec::codecForName(codecName)); - ts.setAutoDetectUnicode(true); - - QString code = ts.readAll(); - QScript::Lexer lexer; - lexer.setCode(code, /*lineNumber=*/1); - QScriptParser parser; - if (!parser.parse(&lexer, cd.m_sourceFileName, &translator)) { - qWarning("%s:%d: %s", qPrintable(cd.m_sourceFileName), parser.errorLineNumber(), - qPrintable(parser.errorMessage())); - return false; - } - - // Java uses UTF-16 internally and Jambi makes UTF-8 for tr() purposes of it. - translator.setCodecName("UTF-8"); - return true; -} - -bool saveQScript(const Translator &translator, QIODevice &dev, ConversionData &cd) -{ - Q_UNUSED(dev); - Q_UNUSED(translator); - cd.appendError(QLatin1String("Cannot save .js files")); - return false; -} - -int initQScript() -{ - Translator::FileFormat format; - format.extension = QLatin1String("js"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("Qt Script source files"); - format.loader = &loadQScript; - format.saver = &saveQScript; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initQScript) - -QT_END_NAMESPACE -./ diff --git a/tools/linguist/shared/translator.cpp b/tools/linguist/shared/translator.cpp index 7babe7a..494cdea 100644 --- a/tools/linguist/shared/translator.cpp +++ b/tools/linguist/shared/translator.cpp @@ -415,6 +415,26 @@ void Translator::dropTranslations() } } +void Translator::dropUiLines() +{ + QString uiXt = QLatin1String(".ui"); + QString juiXt = QLatin1String(".jui"); + for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) { + QHash<QString, int> have; + QList<TranslatorMessage::Reference> refs; + foreach (const TranslatorMessage::Reference &itref, it->allReferences()) { + const QString &fn = itref.fileName(); + if (fn.endsWith(uiXt) || fn.endsWith(juiXt)) { + if (++have[fn] == 1) + refs.append(TranslatorMessage::Reference(fn, -1)); + } else { + refs.append(itref); + } + } + it->setReferences(refs); + } +} + QSet<TranslatorMessagePtr> Translator::resolveDuplicates() { QSet<TranslatorMessagePtr> dups; diff --git a/tools/linguist/shared/translator.h b/tools/linguist/shared/translator.h index ec8d4f2..6c1cd52 100644 --- a/tools/linguist/shared/translator.h +++ b/tools/linguist/shared/translator.h @@ -47,7 +47,9 @@ #include <QDir> #include <QList> #include <QLocale> +#include <QMultiHash> #include <QString> +#include <QSet> QT_BEGIN_NAMESPACE @@ -63,6 +65,7 @@ public: m_ignoreUnfinished(false), m_sortContexts(false), m_noUiLines(false), + m_idBased(false), m_saveMode(SaveEverything) {} @@ -86,13 +89,17 @@ public: QString m_sourceFileName; QString m_targetFileName; QDir m_sourceDir; - QDir m_targetDir; // FIXME: TS spefic + QDir m_targetDir; // FIXME: TS specific + QSet<QString> m_projectRoots; + QMultiHash<QString, QString> m_allCSources; + QStringList m_includePath; QStringList m_dropTags; // tags to be dropped QStringList m_errors; bool m_verbose; bool m_ignoreUnfinished; bool m_sortContexts; bool m_noUiLines; + bool m_idBased; TranslatorSaveMode m_saveMode; }; @@ -128,6 +135,7 @@ public: void stripNonPluralForms(); void stripIdenticalSourceTranslations(); void dropTranslations(); + void dropUiLines(); void makeFileNamesAbsolute(const QDir &originalPath); QSet<TranslatorMessagePtr> resolveDuplicates(); static void reportDuplicates(const QSet<TranslatorMessagePtr> &dupes, @@ -139,7 +147,7 @@ public: QString languageCode() const { return m_language; } QString sourceLanguageCode() const { return m_sourceLanguage; } - enum LocationsType { NoLocations, RelativeLocations, AbsoluteLocations }; + enum LocationsType { DefaultLocations, NoLocations, RelativeLocations, AbsoluteLocations }; void setLocationsType(LocationsType lt) { m_locationsType = lt; } LocationsType locationsType() const { return m_locationsType; } @@ -179,15 +187,15 @@ public: QString description; // human-readable description LoadFunction loader; SaveFunction saver; - enum FileType { SourceCode, TranslationSource, TranslationBinary } fileType; + enum FileType { TranslationSource, TranslationBinary } fileType; int priority; // 0 = highest, -1 = invisible }; static void registerFileFormat(const FileFormat &format); static QList<FileFormat> ®isteredFileFormats(); - enum VariantSeparators { - DefaultVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D - InternalVariantSeparator = 0x9c // unicode "STRING TERMINATOR" + enum { + TextVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D + BinaryVariantSeparator = 0x9c // unicode "STRING TERMINATOR" }; private: diff --git a/tools/linguist/shared/translatortools.cpp b/tools/linguist/shared/translatortools.cpp deleted file mode 100644 index 91298ea..0000000 --- a/tools/linguist/shared/translatortools.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "translatortools.h" - -#include "simtexth.h" -#include "translator.h" - -#include <QtCore/QDebug> -#include <QtCore/QMap> -#include <QtCore/QStringList> -#include <QtCore/QTextCodec> -#include <QtCore/QVector> - -typedef QList<TranslatorMessage> TML; -typedef QMap<QString, TranslatorMessage> TMM; - - -QT_BEGIN_NAMESPACE - -static bool isDigitFriendly(QChar c) -{ - return c.isPunct() || c.isSpace(); -} - -static int numberLength(const QString &s, int i) -{ - if (i < s.size() || !s.at(i).isDigit()) - return 0; - - int pos = i; - do { - ++i; - } while (i < s.size() - && (s.at(i).isDigit() - || (isDigitFriendly(s[i]) - && i + 1 < s.size() - && (s[i + 1].isDigit() - || (isDigitFriendly(s[i + 1]) - && i + 2 < s.size() - && s[i + 2].isDigit()))))); - return i - pos; -} - - -/* - Returns a version of 'key' where all numbers have been replaced by zeroes. If - there were none, returns "". -*/ -static QString zeroKey(const QString &key) -{ - QString zeroed; - bool metSomething = false; - - for (int i = 0; i != key.size(); ++i) { - int len = numberLength(key, i); - if (len > 0) { - i += len; - zeroed.append(QLatin1Char('0')); - metSomething = true; - } else { - zeroed.append(key.at(i)); - } - } - return metSomething ? zeroed : QString(); -} - -static QString translationAttempt(const QString &oldTranslation, - const QString &oldSource, const QString &newSource) -{ - int p = zeroKey(oldSource).count(QLatin1Char('0')); - QString attempt; - QStringList oldNumbers; - QStringList newNumbers; - QVector<bool> met(p); - QVector<int> matchedYet(p); - int i, j; - int k = 0, ell, best; - int m, n; - int pass; - - /* - This algorithm is hard to follow, so we'll consider an example - all along: oldTranslation is "XeT 3.0", oldSource is "TeX 3.0" - and newSource is "XeT 3.1". - - First, we set up two tables: oldNumbers and newNumbers. In our - example, oldNumber[0] is "3.0" and newNumber[0] is "3.1". - */ - for (i = 0, j = 0; i < oldSource.size(); i++, j++) { - m = numberLength(oldSource, i); - n = numberLength(newSource, j); - if (m > 0) { - oldNumbers.append(oldSource.mid(i, m + 1)); - newNumbers.append(newSource.mid(j, n + 1)); - i += m; - j += n; - met[k] = false; - matchedYet[k] = 0; - k++; - } - } - - /* - We now go over the old translation, "XeT 3.0", one letter at a - time, looking for numbers found in oldNumbers. Whenever such a - number is met, it is replaced with its newNumber equivalent. In - our example, the "3.0" of "XeT 3.0" becomes "3.1". - */ - for (i = 0; i < oldTranslation.length(); i++) { - attempt += oldTranslation[i]; - for (k = 0; k < p; k++) { - if (oldTranslation[i] == oldNumbers[k][matchedYet[k]]) - matchedYet[k]++; - else - matchedYet[k] = 0; - } - - /* - Let's find out if the last character ended a match. We make - two passes over the data. In the first pass, we try to - match only numbers that weren't matched yet; if that fails, - the second pass does the trick. This is useful in some - suspicious cases, flagged below. - */ - for (pass = 0; pass < 2; pass++) { - best = p; // an impossible value - for (k = 0; k < p; k++) { - if ((!met[k] || pass > 0) && - matchedYet[k] == oldNumbers[k].length() && - numberLength(oldTranslation, i + 1 - matchedYet[k]) == matchedYet[k]) { - // the longer the better - if (best == p || matchedYet[k] > matchedYet[best]) - best = k; - } - } - if (best != p) { - attempt.truncate(attempt.length() - matchedYet[best]); - attempt += newNumbers[best]; - met[best] = true; - for (k = 0; k < p; k++) - matchedYet[k] = 0; - break; - } - } - } - - /* - We flag two kinds of suspicious cases. They are identified as - such with comments such as "{2000?}" at the end. - - Example of the first kind: old source text "TeX 3.0" translated - as "XeT 2.0" is flagged "TeX 2.0 {3.0?}", no matter what the - new text is. - */ - for (k = 0; k < p; k++) { - if (!met[k]) - attempt += QString(QLatin1String(" {")) + newNumbers[k] + QString(QLatin1String("?}")); - } - - /* - Example of the second kind: "1 of 1" translated as "1 af 1", - with new source text "1 of 2", generates "1 af 2 {1 or 2?}" - because it's not clear which of "1 af 2" and "2 af 1" is right. - */ - for (k = 0; k < p; k++) { - for (ell = 0; ell < p; ell++) { - if (k != ell && oldNumbers[k] == oldNumbers[ell] && - newNumbers[k] < newNumbers[ell]) - attempt += QString(QLatin1String(" {")) + newNumbers[k] + QString(QLatin1String(" or ")) + - newNumbers[ell] + QString(QLatin1String("?}")); - } - } - return attempt; -} - - -/* - Augments a Translator with translations easily derived from - similar existing (probably obsolete) translations. - - For example, if "TeX 3.0" is translated as "XeT 3.0" and "TeX 3.1" - has no translation, "XeT 3.1" is added to the translator and is - marked Unfinished. - - Returns the number of additional messages that this heuristic translated. -*/ -int applyNumberHeuristic(Translator &tor) -{ - TMM translated, untranslated; - TMM::Iterator t, u; - TML all = tor.messages(); - TML::Iterator it; - int inserted = 0; - - for (it = all.begin(); it != all.end(); ++it) { - bool hasTranslation = it->isTranslated(); - if (it->type() == TranslatorMessage::Unfinished) { - if (!hasTranslation) - untranslated.insert(it->context() + QLatin1Char('\n') - + it->sourceText() + QLatin1Char('\n') - + it->comment(), *it); - } else if (hasTranslation && it->translations().count() == 1) { - translated.insert(zeroKey(it->sourceText()), *it); - } - } - - for (u = untranslated.begin(); u != untranslated.end(); ++u) { - t = translated.find(zeroKey((*u).sourceText())); - if (t != translated.end() && !t.key().isEmpty() - && t->sourceText() != u->sourceText()) { - TranslatorMessage m = *u; - m.setTranslation(translationAttempt(t->translation(), t->sourceText(), - u->sourceText())); - tor.replace(m); - inserted++; - } - } - return inserted; -} - - -/* - Augments a Translator with trivially derived translations. - - For example, if "Enabled:" is consistendly translated as "Eingeschaltet:" no - matter the context or the comment, "Eingeschaltet:" is added as the - translation of any untranslated "Enabled:" text and is marked Unfinished. - - Returns the number of additional messages that this heuristic translated. -*/ - -int applySameTextHeuristic(Translator &tor) -{ - TMM translated; - TMM avoid; - TMM::Iterator t; - TML untranslated; - TML::Iterator u; - TML all = tor.messages(); - TML::Iterator it; - int inserted = 0; - - for (it = all.begin(); it != all.end(); ++it) { - if (!it->isTranslated()) { - if (it->type() == TranslatorMessage::Unfinished) - untranslated.append(*it); - } else { - QString key = it->sourceText(); - t = translated.find(key); - if (t != translated.end()) { - /* - The same source text is translated at least two - different ways. Do nothing then. - */ - if (t->translations() != it->translations()) { - translated.remove(key); - avoid.insert(key, *it); - } - } else if (!avoid.contains(key)) { - translated.insert(key, *it); - } - } - } - - for (u = untranslated.begin(); u != untranslated.end(); ++u) { - QString key = u->sourceText(); - t = translated.find(key); - if (t != translated.end()) { - TranslatorMessage m = *u; - m.setTranslations(t->translations()); - tor.replace(m); - ++inserted; - } - } - return inserted; -} - - - -/* - Merges two Translator objects. The first one - is a set of source texts and translations for a previous version of - the internationalized program; the second one is a set of fresh - source texts newly extracted from the source code, without any - translation yet. -*/ - -Translator merge(const Translator &tor, const Translator &virginTor, - UpdateOptions options, QString &err) -{ - int known = 0; - int neww = 0; - int obsoleted = 0; - int similarTextHeuristicCount = 0; - - Translator outTor; - outTor.setLanguageCode(tor.languageCode()); - outTor.setSourceLanguageCode(tor.sourceLanguageCode()); - outTor.setLocationsType(tor.locationsType()); - outTor.setCodecName(tor.codecName()); - - /* - The types of all the messages from the vernacular translator - are updated according to the virgin translator. - */ - foreach (TranslatorMessage m, tor.messages()) { - TranslatorMessage::Type newType = TranslatorMessage::Finished; - - if (m.sourceText().isEmpty()) { - // context/file comment - TranslatorMessage mv = virginTor.find(m.context()); - if (!mv.isNull()) - m.setComment(mv.comment()); - } else { - TranslatorMessage mv = virginTor.find(m.context(), m.sourceText(), m.comment()); - if (mv.isNull()) { - if (!(options & HeuristicSimilarText)) { - newType = TranslatorMessage::Obsolete; - if (m.type() != TranslatorMessage::Obsolete) - obsoleted++; - m.clearReferences(); - } else { - mv = virginTor.find(m.context(), m.comment(), m.allReferences()); - if (mv.isNull()) { - // did not find it in the virgin, mark it as obsolete - newType = TranslatorMessage::Obsolete; - if (m.type() != TranslatorMessage::Obsolete) - obsoleted++; - m.clearReferences(); - } else { - // Do not just accept it if its on the same line number, - // but different source text. - // Also check if the texts are more or less similar before - // we consider them to represent the same message... - if (getSimilarityScore(m.sourceText(), mv.sourceText()) >= textSimilarityThreshold) { - // It is just slightly modified, assume that it is the same string - - // Mark it as unfinished. (Since the source text - // was changed it might require re-translating...) - newType = TranslatorMessage::Unfinished; - ++similarTextHeuristicCount; - neww++; - - m.setOldSourceText(m.sourceText()); - m.setSourceText(mv.sourceText()); - const QString &oldpluralsource = m.extra(QLatin1String("po-msgid_plural")); - if (!oldpluralsource.isEmpty()) { - m.setExtra(QLatin1String("po-old_msgid_plural"), oldpluralsource); - m.unsetExtra(QLatin1String("po-msgid_plural")); - } - m.setReferences(mv.allReferences()); // Update secondary references - m.setPlural(mv.isPlural()); - m.setUtf8(mv.isUtf8()); - m.setExtraComment(mv.extraComment()); - } else { - // The virgin and vernacular sourceTexts are so - // different that we could not find it. - newType = TranslatorMessage::Obsolete; - if (m.type() != TranslatorMessage::Obsolete) - obsoleted++; - m.clearReferences(); - } - } - } - } else { - switch (m.type()) { - case TranslatorMessage::Finished: - default: - if (m.isPlural() == mv.isPlural()) { - newType = TranslatorMessage::Finished; - } else { - newType = TranslatorMessage::Unfinished; - } - known++; - break; - case TranslatorMessage::Unfinished: - newType = TranslatorMessage::Unfinished; - known++; - break; - case TranslatorMessage::Obsolete: - newType = TranslatorMessage::Unfinished; - neww++; - } - - // Always get the filename and linenumber info from the - // virgin Translator, in case it has changed location. - // This should also enable us to read a file that does not - // have the <location> element. - // why not use operator=()? Because it overwrites e.g. userData. - m.setReferences(mv.allReferences()); - m.setPlural(mv.isPlural()); - m.setUtf8(mv.isUtf8()); - m.setExtraComment(mv.extraComment()); - } - } - - m.setType(newType); - outTor.append(m); - } - - /* - Messages found only in the virgin translator are added to the - vernacular translator. - */ - foreach (const TranslatorMessage &mv, virginTor.messages()) { - if (mv.sourceText().isEmpty()) { - if (tor.contains(mv.context())) - continue; - } else { - if (tor.contains(mv.context(), mv.sourceText(), mv.comment())) - continue; - if (options & HeuristicSimilarText) { - TranslatorMessage m = tor.find(mv.context(), mv.comment(), mv.allReferences()); - if (!m.isNull()) { - if (getSimilarityScore(m.sourceText(), mv.sourceText()) >= textSimilarityThreshold) - continue; - } - } - } - if (options & NoLocations) - outTor.append(mv); - else - outTor.appendSorted(mv); - if (!mv.sourceText().isEmpty()) - ++neww; - } - - /* - The same-text heuristic handles cases where a message has an - obsolete counterpart with a different context or comment. - */ - int sameTextHeuristicCount = (options & HeuristicSameText) ? applySameTextHeuristic(outTor) : 0; - - /* - The number heuristic handles cases where a message has an - obsolete counterpart with mostly numbers differing in the - source text. - */ - int sameNumberHeuristicCount = (options & HeuristicNumber) ? applyNumberHeuristic(outTor) : 0; - - if (options & Verbose) { - int totalFound = neww + known; - err += QObject::tr(" Found %n source text(s) (%1 new and %2 already existing)\n", 0, totalFound).arg(neww).arg(known); - - if (obsoleted) { - if (options & NoObsolete) { - err += QObject::tr(" Removed %n obsolete entries\n", 0, obsoleted); - } else { - err += QObject::tr(" Kept %n obsolete entries\n", 0, obsoleted); - } - } - - if (sameNumberHeuristicCount) - err += QObject::tr(" Number heuristic provided %n translation(s)\n", - 0, sameNumberHeuristicCount); - if (sameTextHeuristicCount) - err += QObject::tr(" Same-text heuristic provided %n translation(s)\n", - 0, sameTextHeuristicCount); - if (similarTextHeuristicCount) - err += QObject::tr(" Similar-text heuristic provided %n translation(s)\n", - 0, similarTextHeuristicCount); - } - return outTor; -} - -QT_END_NAMESPACE diff --git a/tools/linguist/shared/translatortools.h b/tools/linguist/shared/translatortools.h deleted file mode 100644 index bba3b3e..0000000 --- a/tools/linguist/shared/translatortools.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef LUPDATE_H -#define LUPDATE_H - -#include "qglobal.h" - -#include <QList> - -QT_BEGIN_NAMESPACE - -class QString; -class Translator; -class TranslatorMessage; - -enum UpdateOption { - Verbose = 1, - NoObsolete = 2, - PluralOnly = 4, - NoSort = 8, - HeuristicSameText = 16, - HeuristicSimilarText = 32, - HeuristicNumber = 64, - AbsoluteLocations = 256, - RelativeLocations = 512, - NoLocations = 1024, - NoUiLines = 2048 -}; - -Q_DECLARE_FLAGS(UpdateOptions, UpdateOption) -Q_DECLARE_OPERATORS_FOR_FLAGS(UpdateOptions) - -Translator merge(const Translator &tor, const Translator &virginTor, - UpdateOptions options, QString &err); - -QT_END_NAMESPACE - -#endif diff --git a/tools/linguist/shared/translatortools.pri b/tools/linguist/shared/translatortools.pri deleted file mode 100644 index 2b6de8c..0000000 --- a/tools/linguist/shared/translatortools.pri +++ /dev/null @@ -1,11 +0,0 @@ - - -INCLUDEPATH *= $$PWD - -SOURCES += \ - $$PWD/translatortools.cpp \ - $$PWD/simtexth.cpp - -HEADERS += \ - $$PWD/translatortools.h - diff --git a/tools/linguist/shared/ts.cpp b/tools/linguist/shared/ts.cpp index 3350940..a7229a3 100644 --- a/tools/linguist/shared/ts.cpp +++ b/tools/linguist/shared/ts.cpp @@ -197,7 +197,7 @@ QString TSReader::readTransContents() // ignore these, just whitespace } else if (elementStarts(strlengthvariant)) { if (!result.isEmpty()) - result += QChar(Translator::DefaultVariantSeparator); + result += QChar(Translator::BinaryVariantSeparator); result += readContents(); } else { handleError(); @@ -514,7 +514,7 @@ static void writeExtras(QTextStream &t, const char *indent, static void writeVariants(QTextStream &t, const char *indent, const QString &input) { int offset; - if ((offset = input.indexOf(QChar(Translator::DefaultVariantSeparator))) >= 0) { + if ((offset = input.indexOf(QChar(Translator::BinaryVariantSeparator))) >= 0) { t << " variants=\"yes\">"; int start = 0; forever { @@ -524,7 +524,7 @@ static void writeVariants(QTextStream &t, const char *indent, const QString &inp if (offset == input.length()) break; start = offset + 1; - offset = input.indexOf(QChar(Translator::DefaultVariantSeparator), start); + offset = input.indexOf(QChar(Translator::BinaryVariantSeparator), start); if (offset < 0) offset = input.length(); } diff --git a/tools/linguist/shared/ts.dtd b/tools/linguist/shared/ts.dtd index cfbc786..4d2cdeb 100644 --- a/tools/linguist/shared/ts.dtd +++ b/tools/linguist/shared/ts.dtd @@ -34,7 +34,7 @@ version CDATA #IMPLIED sourcelanguage CDATA #IMPLIED language CDATA #IMPLIED> -<!-- The encoding to use in the .qm file by default. Default is ISO-8859-1. --> +<!-- The encoding to use in the QM file by default. Default is ISO-8859-1. --> <!ELEMENT defaultcodec (#PCDATA) > <!ELEMENT context (name?, comment?, (context|message)+) > <!ATTLIST context @@ -54,7 +54,7 @@ <!ELEMENT message (location*, source?, oldsource?, comment?, oldcomment?, extracomment?, translatorcomment?, translation?, userdata?, extra-**) > <!-- ! If utf8 is true, the defaultcodec is overridden and the message is encoded - ! in UTF-8 in the .qm file. + ! in UTF-8 in the QM file. --> <!ATTLIST message id CDATA #IMPLIED @@ -70,7 +70,7 @@ ! is omitted, the "current" one is used. For the 1st location in a message, ! "current" is the filename used for the 1st location of the previous message. ! For subsequent locations, it is the filename used for the previous location. - ! A single .ts file has either all absolute or all relative locations. + ! A single TS file has either all absolute or all relative locations. --> <!ATTLIST location filename CDATA #IMPLIED @@ -100,5 +100,14 @@ --> <!ELEMENT numerusform (#PCDATA|byte|lengthvariant)* > <!ATTLIST numerusform + plurality (nullar|singular|dual|trial|paucal|greaterpaucal|plural|greaterplural) #IMPLIED> variants (yes|no) "no"> <!ELEMENT lengthvariant %evilstring; > +<!-- + ! The translation variants have a priority between 1 ("highest") and 9 ("lowest") + ! Typically longer translations get a higher priority. + ! If omitted, the order of appearance of the variants in the TS files is used. + --> +<!ATTLIST lengthvariant + priority (1|2|3|4|5|6|7|8|9) #IMPLIED> + diff --git a/tools/linguist/shared/ui.cpp b/tools/linguist/shared/ui.cpp deleted file mode 100644 index 8dc798a..0000000 --- a/tools/linguist/shared/ui.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "translator.h" - -#include <QtCore/QDebug> -#include <QtCore/QFile> -#include <QtCore/QString> - -#include <QtXml/QXmlAttributes> -#include <QtXml/QXmlDefaultHandler> -#include <QtXml/QXmlLocator> -#include <QtXml/QXmlParseException> - - -QT_BEGIN_NAMESPACE - -// in cpp.cpp -void fetchtrInlinedCpp(const QString &in, Translator &tor, const QString &context); - -class UiReader : public QXmlDefaultHandler -{ -public: - UiReader(Translator &translator, ConversionData &cd) - : m_translator(translator), m_cd(cd), m_lineNumber(-1), m_isTrString(false), - m_needUtf8(translator.codecName() != "UTF-8") - {} - - bool startElement(const QString &namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts); - bool endElement(const QString &namespaceURI, const QString &localName, - const QString &qName); - bool characters(const QString &ch); - bool fatalError(const QXmlParseException &exception); - - void setDocumentLocator(QXmlLocator *locator) { m_locator = locator; } - -private: - void flush(); - - Translator &m_translator; - ConversionData &m_cd; - QString m_context; - QString m_source; - QString m_comment; - QString m_extracomment; - QXmlLocator *m_locator; - - QString m_accum; - int m_lineNumber; - bool m_isTrString; - bool m_needUtf8; -}; - -bool UiReader::startElement(const QString &namespaceURI, - const QString &localName, const QString &qName, const QXmlAttributes &atts) -{ - Q_UNUSED(namespaceURI); - Q_UNUSED(localName); - - if (qName == QLatin1String("item")) { // UI3 menu entries - flush(); - if (!atts.value(QLatin1String("text")).isEmpty()) { - m_source = atts.value(QLatin1String("text")); - m_isTrString = true; - if (!m_cd.m_noUiLines) - m_lineNumber = m_locator->lineNumber(); - } - } else if (qName == QLatin1String("string")) { - flush(); - if (atts.value(QLatin1String("notr")).isEmpty() || - atts.value(QLatin1String("notr")) != QLatin1String("true")) { - m_isTrString = true; - m_comment = atts.value(QLatin1String("comment")); - m_extracomment = atts.value(QLatin1String("extracomment")); - if (!m_cd.m_noUiLines) - m_lineNumber = m_locator->lineNumber(); - } else { - m_isTrString = false; - } - } - m_accum.clear(); - return true; -} - -bool UiReader::endElement(const QString &namespaceURI, - const QString &localName, const QString &qName) -{ - Q_UNUSED(namespaceURI); - Q_UNUSED(localName); - - m_accum.replace(QLatin1String("\r\n"), QLatin1String("\n")); - - if (qName == QLatin1String("class")) { // UI "header" - if (m_context.isEmpty()) - m_context = m_accum; - } else if (qName == QLatin1String("string") && m_isTrString) { - m_source = m_accum; - } else if (qName == QLatin1String("comment")) { // FIXME: what's that? - m_comment = m_accum; - flush(); - } else if (qName == QLatin1String("function")) { // UI3 embedded code - fetchtrInlinedCpp(m_accum, m_translator, m_context); - } else { - flush(); - } - return true; -} - -bool UiReader::characters(const QString &ch) -{ - m_accum += ch; - return true; -} - -bool UiReader::fatalError(const QXmlParseException &exception) -{ - QString msg; - msg.sprintf("XML error: Parse error at line %d, column %d (%s).", - exception.lineNumber(), exception.columnNumber(), - exception.message().toLatin1().data()); - m_cd.appendError(msg); - return false; -} - -void UiReader::flush() -{ - if (!m_context.isEmpty() && !m_source.isEmpty()) { - TranslatorMessage msg(m_context, m_source, - m_comment, QString(), m_cd.m_sourceFileName, - m_lineNumber, QStringList()); - msg.setExtraComment(m_extracomment); - if (m_needUtf8 && msg.needs8Bit()) - msg.setUtf8(true); - m_translator.extend(msg); - } - m_source.clear(); - m_comment.clear(); - m_extracomment.clear(); -} - -bool loadUI(Translator &translator, QIODevice &dev, ConversionData &cd) -{ - QXmlInputSource in(&dev); - QXmlSimpleReader reader; - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false); - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true); - reader.setFeature(QLatin1String( - "http://trolltech.com/xml/features/report-whitespace-only-CharData"), false); - UiReader handler(translator, cd); - reader.setContentHandler(&handler); - reader.setErrorHandler(&handler); - bool result = reader.parse(in); - if (!result) - cd.appendError(QLatin1String("Parse error in UI file")); - reader.setContentHandler(0); - reader.setErrorHandler(0); - return result; -} - -bool saveUI(const Translator &translator, QIODevice &dev, ConversionData &cd) -{ - Q_UNUSED(dev); - Q_UNUSED(translator); - cd.appendError(QLatin1String("Cannot save .ui files")); - return false; -} - -int initUI() -{ - Translator::FileFormat format; - - // "real" Qt Designer - format.extension = QLatin1String("ui"); - format.description = QObject::tr("Qt Designer form files"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.loader = &loadUI; - format.saver = &saveUI; - Translator::registerFileFormat(format); - - // same for jambi - format.extension = QLatin1String("jui"); - format.description = QObject::tr("Qt Jambi form files"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.loader = &loadUI; - format.saver = &saveUI; - Translator::registerFileFormat(format); - - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initUI) - -QT_END_NAMESPACE diff --git a/tools/linguist/shared/xliff.cpp b/tools/linguist/shared/xliff.cpp index a3c424d..1285b44 100644 --- a/tools/linguist/shared/xliff.cpp +++ b/tools/linguist/shared/xliff.cpp @@ -302,6 +302,8 @@ static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QString translation; if (transit != transend) { translation = *transit; + translation.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); ++transit; puttrans = true; } @@ -596,8 +598,11 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN m_sources.append(accum); } } else if (localName == QLatin1String("target")) { - if (popContext(XC_restype_translation)) + if (popContext(XC_restype_translation)) { + accum.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); m_translations.append(accum); + } } else if (localName == QLatin1String("context-group")) { if (popContext(XC_context_group)) { m_refs.append(TranslatorMessage::Reference( |