tools/linguist/lupdate/qscript.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
    45 
    45 
    46 #define Q_SCRIPT_REGEXPLITERAL_RULE2 8
    46 #define Q_SCRIPT_REGEXPLITERAL_RULE2 8
    47 
    47 
    48 #include <translator.h>
    48 #include <translator.h>
    49 
    49 
       
    50 #include <QtCore/QCoreApplication>
    50 #include <QtCore/qdebug.h>
    51 #include <QtCore/qdebug.h>
    51 #include <QtCore/qnumeric.h>
    52 #include <QtCore/qnumeric.h>
    52 #include <QtCore/qstring.h>
    53 #include <QtCore/qstring.h>
    53 #include <QtCore/qtextcodec.h>
    54 #include <QtCore/qtextcodec.h>
    54 #include <QtCore/qvariant.h>
    55 #include <QtCore/qvariant.h>
    59 #include <stdlib.h>
    60 #include <stdlib.h>
    60 #include <stdio.h>
    61 #include <stdio.h>
    61 #include <string.h>
    62 #include <string.h>
    62 
    63 
    63 QT_BEGIN_NAMESPACE
    64 QT_BEGIN_NAMESPACE
       
    65 
       
    66 class LU {
       
    67     Q_DECLARE_TR_FUNCTIONS(LUpdate)
       
    68 };
    64 
    69 
    65 class QScriptGrammar
    70 class QScriptGrammar
    66 {
    71 {
    67 public:
    72 public:
    68   enum {
    73   enum {
   768   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   773   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   769   -1, -1};
   774   -1, -1};
   770 
   775 
   771 static void recordMessage(
   776 static void recordMessage(
   772     Translator *tor, const QString &context, const QString &text, const QString &comment,
   777     Translator *tor, const QString &context, const QString &text, const QString &comment,
   773     const QString &extracomment, bool plural, const QString &fileName, int lineNo)
   778     const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra,
       
   779     bool plural, const QString &fileName, int lineNo)
   774 {
   780 {
   775     TranslatorMessage msg(
   781     TranslatorMessage msg(
   776         context, text, comment, QString(),
   782         context, text, comment, QString(),
   777         fileName, lineNo, QStringList(),
   783         fileName, lineNo, QStringList(),
   778         TranslatorMessage::Unfinished, plural);
   784         TranslatorMessage::Unfinished, plural);
   779     msg.setExtraComment(extracomment.simplified());
   785     msg.setExtraComment(extracomment.simplified());
       
   786     msg.setId(msgid);
       
   787     msg.setExtras(extra);
   780     tor->extend(msg);
   788     tor->extend(msg);
   781 }
   789 }
   782 
   790 
   783 
   791 
   784 namespace QScript
   792 namespace QScript
   785 {
   793 {
   786 
   794 
       
   795 class CommentProcessor
       
   796 {
       
   797 public:
       
   798     virtual ~CommentProcessor() {}
       
   799     virtual void processComment(const QChar *chars, int length) = 0;
       
   800 };
       
   801 
   787 class Lexer
   802 class Lexer
   788 {
   803 {
   789 public:
   804 public:
   790     Lexer();
   805     Lexer(CommentProcessor *);
   791     ~Lexer();
   806     ~Lexer();
   792 
   807 
   793     void setCode(const QString &c, int lineno);
   808     void setCode(const QString &c, const QString &fileName, int lineno);
   794     int lex();
   809     int lex();
   795 
   810 
       
   811     QString fileName() const { return yyfilename; }
   796     int currentLineNo() const { return yylineno; }
   812     int currentLineNo() const { return yylineno; }
   797     int currentColumnNo() const { return yycolumn; }
   813     int currentColumnNo() const { return yycolumn; }
   798 
   814 
   799     int startLineNo() const { return startlineno; }
   815     int startLineNo() const { return startlineno; }
   800     int startColumnNo() const { return startcolumn; }
   816     int startColumnNo() const { return startcolumn; }
   870         { return err; }
   886         { return err; }
   871     void clearError()
   887     void clearError()
   872         { err = NoError; }
   888         { err = NoError; }
   873 
   889 
   874 private:
   890 private:
       
   891     QString yyfilename;
   875     int yylineno;
   892     int yylineno;
   876     bool done;
   893     bool done;
   877     char *buffer8;
   894     char *buffer8;
   878     QChar *buffer16;
   895     QChar *buffer16;
   879     uint size8, size16;
   896     uint size8, size16;
   923 
   940 
   924     int findReservedWord(const QChar *buffer, int size) const;
   941     int findReservedWord(const QChar *buffer, int size) const;
   925 
   942 
   926     void syncProhibitAutomaticSemicolon();
   943     void syncProhibitAutomaticSemicolon();
   927 
   944 
       
   945     void processComment(const QChar *, int);
       
   946 
   928     const QChar *code;
   947     const QChar *code;
   929     uint length;
   948     uint length;
   930     int yycolumn;
   949     int yycolumn;
   931     int startlineno;
   950     int startlineno;
   932     int startcolumn;
   951     int startcolumn;
   949     bool check_reserved;
   968     bool check_reserved;
   950 
   969 
   951     ParenthesesState parenthesesState;
   970     ParenthesesState parenthesesState;
   952     int parenthesesCount;
   971     int parenthesesCount;
   953     bool prohibitAutomaticSemicolon;
   972     bool prohibitAutomaticSemicolon;
       
   973 
       
   974     CommentProcessor *commentProcessor;
   954 };
   975 };
   955 
   976 
   956 } // namespace QScript
   977 } // namespace QScript
   957 
   978 
   958 extern double qstrtod(const char *s00, char const **se, bool *ok);
   979 extern double qstrtod(const char *s00, char const **se, bool *ok);
  1025     return result;
  1046     return result;
  1026 }
  1047 }
  1027 
  1048 
  1028 } // namespace QScript
  1049 } // namespace QScript
  1029 
  1050 
  1030 QScript::Lexer::Lexer()
  1051 QScript::Lexer::Lexer(QScript::CommentProcessor *proc)
  1031     :
  1052     :
  1032       yylineno(0),
  1053       yylineno(0),
  1033       size8(128), size16(128), restrKeyword(false),
  1054       size8(128), size16(128), restrKeyword(false),
  1034       stackToken(-1), pos(0),
  1055       stackToken(-1), pos(0),
  1035       code(0), length(0),
  1056       code(0), length(0),
  1036       bol(true),
  1057       bol(true),
  1037       current(0), next1(0), next2(0), next3(0),
  1058       current(0), next1(0), next2(0), next3(0),
  1038       err(NoError),
  1059       err(NoError),
  1039       check_reserved(true),
  1060       check_reserved(true),
  1040       parenthesesState(IgnoreParentheses),
  1061       parenthesesState(IgnoreParentheses),
  1041       prohibitAutomaticSemicolon(false)
  1062       prohibitAutomaticSemicolon(false),
       
  1063       commentProcessor(proc)
  1042 {
  1064 {
  1043     // allocate space for read buffers
  1065     // allocate space for read buffers
  1044     buffer8 = new char[size8];
  1066     buffer8 = new char[size8];
  1045     buffer16 = new QChar[size16];
  1067     buffer16 = new QChar[size16];
  1046     flags = 0;
  1068     flags = 0;
  1051 {
  1073 {
  1052     delete [] buffer8;
  1074     delete [] buffer8;
  1053     delete [] buffer16;
  1075     delete [] buffer16;
  1054 }
  1076 }
  1055 
  1077 
  1056 void QScript::Lexer::setCode(const QString &c, int lineno)
  1078 void QScript::Lexer::setCode(const QString &c, const QString &fileName, int lineno)
  1057 {
  1079 {
  1058     errmsg = QString();
  1080     errmsg = QString();
       
  1081     yyfilename = fileName;
  1059     yylineno = lineno;
  1082     yylineno = lineno;
  1060     yycolumn = 1;
  1083     yycolumn = 1;
  1061     restrKeyword = false;
  1084     restrKeyword = false;
  1062     delimited = false;
  1085     delimited = false;
  1063     stackToken = -1;
  1086     stackToken = -1;
  1402             if (isWhiteSpace()) {
  1425             if (isWhiteSpace()) {
  1403                 // do nothing
  1426                 // do nothing
  1404             } else if (current == '/' && next1 == '/') {
  1427             } else if (current == '/' && next1 == '/') {
  1405                 recordStartPos();
  1428                 recordStartPos();
  1406                 shift(1);
  1429                 shift(1);
       
  1430                 Q_ASSERT(pos16 == 0);
  1407                 state = InSingleLineComment;
  1431                 state = InSingleLineComment;
  1408             } else if (current == '/' && next1 == '*') {
  1432             } else if (current == '/' && next1 == '*') {
  1409                 recordStartPos();
  1433                 recordStartPos();
  1410                 shift(1);
  1434                 shift(1);
       
  1435                 Q_ASSERT(pos16 == 0);
  1411                 state = InMultiLineComment;
  1436                 state = InMultiLineComment;
  1412             } else if (current == 0) {
  1437             } else if (current == 0) {
  1413                 syncProhibitAutomaticSemicolon();
  1438                 syncProhibitAutomaticSemicolon();
  1414                 if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
  1439                 if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
  1415                     // automatic semicolon insertion if program incomplete
  1440                     // automatic semicolon insertion if program incomplete
  1464                     setDone(Other);
  1489                     setDone(Other);
  1465                 }
  1490                 }
  1466                 else {
  1491                 else {
  1467                     setDone(Bad);
  1492                     setDone(Bad);
  1468                     err = IllegalCharacter;
  1493                     err = IllegalCharacter;
  1469                     errmsg = QLatin1String("Illegal character");
  1494                     errmsg = LU::tr("Illegal character");
  1470                 }
  1495                 }
  1471             }
  1496             }
  1472             break;
  1497             break;
  1473         case InString:
  1498         case InString:
  1474             if (current == stringType) {
  1499             if (current == stringType) {
  1475                 shift(1);
  1500                 shift(1);
  1476                 setDone(String);
  1501                 setDone(String);
  1477             } else if (current == 0 || isLineTerminator()) {
  1502             } else if (current == 0 || isLineTerminator()) {
  1478                 setDone(Bad);
  1503                 setDone(Bad);
  1479                 err = UnclosedStringLiteral;
  1504                 err = UnclosedStringLiteral;
  1480                 errmsg = QLatin1String("Unclosed string at end of line");
  1505                 errmsg = LU::tr("Unclosed string at end of line");
  1481             } else if (current == '\\') {
  1506             } else if (current == '\\') {
  1482                 state = InEscapeSequence;
  1507                 state = InEscapeSequence;
  1483             } else {
  1508             } else {
  1484                 record16(current);
  1509                 record16(current);
  1485             }
  1510             }
  1501                     record16(convertOctal('0', '0', current));
  1526                     record16(convertOctal('0', '0', current));
  1502                     state = InString;
  1527                     state = InString;
  1503                 } else {
  1528                 } else {
  1504                     setDone(Bad);
  1529                     setDone(Bad);
  1505                     err = IllegalEscapeSequence;
  1530                     err = IllegalEscapeSequence;
  1506                     errmsg = QLatin1String("Illegal escape squence");
  1531                     errmsg = LU::tr("Illegal escape squence");
  1507                 }
  1532                 }
  1508             } else if (current == 'x')
  1533             } else if (current == 'x')
  1509                 state = InHexEscape;
  1534                 state = InHexEscape;
  1510             else if (current == 'u')
  1535             else if (current == 'u')
  1511                 state = InUnicodeEscape;
  1536                 state = InUnicodeEscape;
  1540                 shift(1);
  1565                 shift(1);
  1541                 setDone(String);
  1566                 setDone(String);
  1542             } else {
  1567             } else {
  1543                 setDone(Bad);
  1568                 setDone(Bad);
  1544                 err = IllegalUnicodeEscapeSequence;
  1569                 err = IllegalUnicodeEscapeSequence;
  1545                 errmsg = QLatin1String("Illegal unicode escape sequence");
  1570                 errmsg = LU::tr("Illegal unicode escape sequence");
  1546             }
  1571             }
  1547             break;
  1572             break;
  1548         case InSingleLineComment:
  1573         case InSingleLineComment:
  1549             if (isLineTerminator()) {
  1574             if (isLineTerminator()) {
       
  1575                 record16(current); // include newline
       
  1576                 processComment(buffer16, pos16);
  1550                 shiftWindowsLineBreak();
  1577                 shiftWindowsLineBreak();
  1551                 yylineno++;
  1578                 yylineno++;
  1552                 yycolumn = 0;
  1579                 yycolumn = 0;
       
  1580                 pos16 = 0;
  1553                 terminator = true;
  1581                 terminator = true;
  1554                 bol = true;
  1582                 bol = true;
  1555                 if (restrKeyword) {
  1583                 if (restrKeyword) {
  1556                     token = QScriptGrammar::T_SEMICOLON;
  1584                     token = QScriptGrammar::T_SEMICOLON;
  1557                     setDone(Other);
  1585                     setDone(Other);
  1558                 } else
  1586                 } else
  1559                     state = Start;
  1587                     state = Start;
  1560             } else if (current == 0) {
  1588             } else if (current == 0) {
  1561                 setDone(Eof);
  1589                 setDone(Eof);
       
  1590             } else {
       
  1591                 record16(current);
  1562             }
  1592             }
  1563             break;
  1593             break;
  1564         case InMultiLineComment:
  1594         case InMultiLineComment:
  1565             if (current == 0) {
  1595             if (current == 0) {
  1566                 setDone(Bad);
  1596                 setDone(Bad);
  1567                 err = UnclosedComment;
  1597                 err = UnclosedComment;
  1568                 errmsg = QLatin1String("Unclosed comment at end of file");
  1598                 errmsg = LU::tr("Unclosed comment at end of file");
  1569             } else if (isLineTerminator()) {
  1599             } else if (isLineTerminator()) {
  1570                 shiftWindowsLineBreak();
  1600                 shiftWindowsLineBreak();
  1571                 yylineno++;
  1601                 yylineno++;
  1572             } else if (current == '*' && next1 == '/') {
  1602             } else if (current == '*' && next1 == '/') {
       
  1603                 processComment(buffer16, pos16);
       
  1604                 pos16 = 0;
  1573                 state = Start;
  1605                 state = Start;
  1574                 shift(1);
  1606                 shift(1);
       
  1607             } else {
       
  1608                 record16(current);
  1575             }
  1609             }
  1576             break;
  1610             break;
  1577         case InIdentifier:
  1611         case InIdentifier:
  1578             if (isIdentLetter(current) || isDecimalDigit(current)) {
  1612             if (isIdentLetter(current) || isDecimalDigit(current)) {
  1579                 record16(current);
  1613                 record16(current);
  1647                 record8(current);
  1681                 record8(current);
  1648                 state = InExponent;
  1682                 state = InExponent;
  1649             } else {
  1683             } else {
  1650                 setDone(Bad);
  1684                 setDone(Bad);
  1651                 err = IllegalExponentIndicator;
  1685                 err = IllegalExponentIndicator;
  1652                 errmsg = QLatin1String("Illegal syntax for exponential number");
  1686                 errmsg = LU::tr("Illegal syntax for exponential number");
  1653             }
  1687             }
  1654             break;
  1688             break;
  1655         case InExponent:
  1689         case InExponent:
  1656             if (isDecimalDigit(current)) {
  1690             if (isDecimalDigit(current)) {
  1657                 record8(current);
  1691                 record8(current);
  1673     // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
  1707     // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
  1674     if ((state == Number || state == Octal || state == Hex)
  1708     if ((state == Number || state == Octal || state == Hex)
  1675          && isIdentLetter(current)) {
  1709          && isIdentLetter(current)) {
  1676         state = Bad;
  1710         state = Bad;
  1677         err = IllegalIdentifier;
  1711         err = IllegalIdentifier;
  1678         errmsg = QLatin1String("Identifier cannot start with numeric literal");
  1712         errmsg = LU::tr("Identifier cannot start with numeric literal");
  1679     }
  1713     }
  1680 
  1714 
  1681     // terminate string
  1715     // terminate string
  1682     buffer8[pos8] = '\0';
  1716     buffer8[pos8] = '\0';
  1683 
  1717 
  1992     if (prefix == EqualPrefix)
  2026     if (prefix == EqualPrefix)
  1993         record16(QLatin1Char('='));
  2027         record16(QLatin1Char('='));
  1994 
  2028 
  1995     while (1) {
  2029     while (1) {
  1996         if (isLineTerminator() || current == 0) {
  2030         if (isLineTerminator() || current == 0) {
  1997             errmsg = QLatin1String("Unterminated regular expression literal");
  2031             errmsg = LU::tr("Unterminated regular expression literal");
  1998             return false;
  2032             return false;
  1999         }
  2033         }
  2000         else if (current != '/' || lastWasEscape == true)
  2034         else if (current != '/' || lastWasEscape == true)
  2001             {
  2035             {
  2002                 record16(current);
  2036                 record16(current);
  2031     } else {
  2065     } else {
  2032         prohibitAutomaticSemicolon = false;
  2066         prohibitAutomaticSemicolon = false;
  2033     }
  2067     }
  2034 }
  2068 }
  2035 
  2069 
       
  2070 void QScript::Lexer::processComment(const QChar *chars, int length)
       
  2071 {
       
  2072     commentProcessor->processComment(chars, length);
       
  2073 }
       
  2074 
  2036 
  2075 
  2037 class Translator;
  2076 class Translator;
  2038 
  2077 
  2039 class QScriptParser: protected QScriptGrammar
  2078 class QScriptParser: protected QScriptGrammar, public QScript::CommentProcessor
  2040 {
  2079 {
  2041 public:
  2080 public:
  2042     QVariant val;
  2081     QVariant val;
  2043 
  2082 
  2044     struct Location {
  2083     struct Location {
  2050 
  2089 
  2051 public:
  2090 public:
  2052     QScriptParser();
  2091     QScriptParser();
  2053     ~QScriptParser();
  2092     ~QScriptParser();
  2054 
  2093 
  2055     bool parse(QScript::Lexer *lexer,
  2094     void setLexer(QScript::Lexer *);
  2056                const QString &fileName,
  2095 
  2057                Translator *translator);
  2096     bool parse(Translator *translator);
  2058 
  2097 
       
  2098     QString fileName() const
       
  2099     { return lexer->fileName(); }
  2059     inline QString errorMessage() const
  2100     inline QString errorMessage() const
  2060     { return error_message; }
  2101     { return error_message; }
  2061     inline int errorLineNumber() const
  2102     inline int errorLineNumber() const
  2062     { return error_lineno; }
  2103     { return error_lineno; }
  2063     inline int errorColumnNumber() const
  2104     inline int errorColumnNumber() const
  2069     inline QVariant &sym(int index)
  2110     inline QVariant &sym(int index)
  2070     { return sym_stack [tos + index - 1]; }
  2111     { return sym_stack [tos + index - 1]; }
  2071 
  2112 
  2072     inline Location &loc(int index)
  2113     inline Location &loc(int index)
  2073     { return location_stack [tos + index - 2]; }
  2114     { return location_stack [tos + index - 2]; }
       
  2115 
       
  2116     std::ostream &yyMsg(int line = 0);
       
  2117 
       
  2118     virtual void processComment(const QChar *, int);
  2074 
  2119 
  2075 protected:
  2120 protected:
  2076     int tos;
  2121     int tos;
  2077     int stack_size;
  2122     int stack_size;
  2078     QVector<QVariant> sym_stack;
  2123     QVector<QVariant> sym_stack;
  2079     int *state_stack;
  2124     int *state_stack;
  2080     Location *location_stack;
  2125     Location *location_stack;
  2081     QString error_message;
  2126     QString error_message;
  2082     int error_lineno;
  2127     int error_lineno;
  2083     int error_column;
  2128     int error_column;
       
  2129 
       
  2130 private:
       
  2131     QScript::Lexer *lexer;
       
  2132     QString extracomment;
       
  2133     QString msgid;
       
  2134     QString sourcetext;
       
  2135     TranslatorMessage::ExtraData extra;
  2084 };
  2136 };
  2085 
  2137 
  2086 inline void QScriptParser::reallocateStack()
  2138 inline void QScriptParser::reallocateStack()
  2087 {
  2139 {
  2088     if (! stack_size)
  2140     if (! stack_size)
  2105 QScriptParser::QScriptParser():
  2157 QScriptParser::QScriptParser():
  2106     tos(0),
  2158     tos(0),
  2107     stack_size(0),
  2159     stack_size(0),
  2108     sym_stack(0),
  2160     sym_stack(0),
  2109     state_stack(0),
  2161     state_stack(0),
  2110     location_stack(0)
  2162     location_stack(0),
       
  2163     lexer(0)
  2111 {
  2164 {
  2112 }
  2165 }
  2113 
  2166 
  2114 QScriptParser::~QScriptParser()
  2167 QScriptParser::~QScriptParser()
  2115 {
  2168 {
  2127     loc.endLine = lexer->endLineNo();
  2180     loc.endLine = lexer->endLineNo();
  2128     loc.endColumn = lexer->endColumnNo();
  2181     loc.endColumn = lexer->endColumnNo();
  2129     return loc;
  2182     return loc;
  2130 }
  2183 }
  2131 
  2184 
  2132 bool QScriptParser::parse(QScript::Lexer *lexer,
  2185 void QScriptParser::setLexer(QScript::Lexer *lex)
  2133                     const QString &fileName,
  2186 {
  2134      	            Translator *translator)
  2187     lexer = lex;
  2135 {
  2188 }
       
  2189 
       
  2190 bool QScriptParser::parse(Translator *translator)
       
  2191 {
       
  2192   Q_ASSERT(lexer != 0);
  2136   const int INITIAL_STATE = 0;
  2193   const int INITIAL_STATE = 0;
  2137 
  2194 
  2138   int yytoken = -1;
  2195   int yytoken = -1;
  2139   int saved_yytoken = -1;
  2196   int saved_yytoken = -1;
  2140   int identLineNo = -1;
  2197   int identLineNo = -1;
  2212 } break;
  2269 } break;
  2213 
  2270 
  2214 case 66: {
  2271 case 66: {
  2215     QString name = sym(1).toString();
  2272     QString name = sym(1).toString();
  2216     if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) {
  2273     if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) {
       
  2274         if (!sourcetext.isEmpty())
       
  2275             yyMsg(identLineNo) << qPrintable(LU::tr("//% cannot be used with %1(). Ignoring\n").arg(name));
  2217         QVariantList args = sym(2).toList();
  2276         QVariantList args = sym(2).toList();
  2218         if (args.size() < 2) {
  2277         if (args.size() < 2) {
  2219             std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  2278             yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least two arguments.\n").arg(name));
  2220                       << qPrintable(name) << "() requires at least two arguments.\n";
       
  2221         } else {
  2279         } else {
  2222             if ((args.at(0).type() != QVariant::String)
  2280             if ((args.at(0).type() != QVariant::String)
  2223                 || (args.at(1).type() != QVariant::String)) {
  2281                 || (args.at(1).type() != QVariant::String)) {
  2224                 std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  2282                 yyMsg(identLineNo) << qPrintable(LU::tr("%1(): both arguments must be literal strings.\n").arg(name));
  2225                           << qPrintable(name) << "(): both arguments must be literal strings.\n";
       
  2226             } else {
  2283             } else {
  2227                 QString context = args.at(0).toString();
  2284                 QString context = args.at(0).toString();
  2228                 QString text = args.at(1).toString();
  2285                 QString text = args.at(1).toString();
  2229                 QString comment = args.value(2).toString();
  2286                 QString comment = args.value(2).toString();
  2230                 QString extracomment;
       
  2231                 bool plural = (args.size() > 4);
  2287                 bool plural = (args.size() > 4);
  2232                 recordMessage(translator, context, text, comment, extracomment,
  2288                 recordMessage(translator, context, text, comment, extracomment,
  2233                               plural, fileName, identLineNo);
  2289                               msgid, extra, plural, fileName(), identLineNo);
  2234             }
  2290             }
  2235         }
  2291         }
       
  2292         sourcetext.clear();
       
  2293         extracomment.clear();
       
  2294         msgid.clear();
       
  2295         extra.clear();
  2236     } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) {
  2296     } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) {
       
  2297         if (!sourcetext.isEmpty())
       
  2298             yyMsg(identLineNo) << qPrintable(LU::tr("//% cannot be used with %1(). Ignoring\n").arg(name));
  2237         QVariantList args = sym(2).toList();
  2299         QVariantList args = sym(2).toList();
  2238         if (args.size() < 1) {
  2300         if (args.size() < 1) {
  2239             std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  2301             yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least one argument.\n").arg(name));
  2240                       << qPrintable(name) << "() requires at least one argument.\n";
       
  2241         } else {
  2302         } else {
  2242             if (args.at(0).type() != QVariant::String) {
  2303             if (args.at(0).type() != QVariant::String) {
  2243                 std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  2304                 yyMsg(identLineNo) << qPrintable(LU::tr("%1(): text to translate must be a literal string.\n").arg(name));
  2244                           << qPrintable(name) << "(): text to translate must be a literal string.\n";
       
  2245             } else {
  2305             } else {
  2246                 QString context = QFileInfo(fileName).baseName();
  2306                 QString context = QFileInfo(fileName()).baseName();
  2247                 QString text = args.at(0).toString();
  2307                 QString text = args.at(0).toString();
  2248                 QString comment = args.value(1).toString();
  2308                 QString comment = args.value(1).toString();
  2249                 QString extracomment;
       
  2250                 bool plural = (args.size() > 2);
  2309                 bool plural = (args.size() > 2);
  2251                 recordMessage(translator, context, text, comment, extracomment,
  2310                 recordMessage(translator, context, text, comment, extracomment,
  2252                               plural, fileName, identLineNo);
  2311                               msgid, extra, plural, fileName(), identLineNo);
  2253             }
  2312             }
  2254         }
  2313         }
       
  2314         sourcetext.clear();
       
  2315         extracomment.clear();
       
  2316         msgid.clear();
       
  2317         extra.clear();
       
  2318     } else if ((name == QLatin1String("qsTrId")) || (name == QLatin1String("QT_TRID_NOOP"))) {
       
  2319         if (!msgid.isEmpty())
       
  2320             yyMsg(identLineNo) << qPrintable(LU::tr("//= cannot be used with %1(). Ignoring\n").arg(name));
       
  2321         QVariantList args = sym(2).toList();
       
  2322         if (args.size() < 1) {
       
  2323             yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least one argument.\n").arg(name));
       
  2324         } else {
       
  2325             if (args.at(0).type() != QVariant::String) {
       
  2326                 yyMsg(identLineNo) << qPrintable(LU::tr("%1(): identifier must be a literal string.\n").arg(name));
       
  2327             } else {
       
  2328                 msgid = args.at(0).toString();
       
  2329                 bool plural = (args.size() > 1);
       
  2330                 recordMessage(translator, QString(), sourcetext, QString(), extracomment,
       
  2331                               msgid, extra, plural, fileName(), identLineNo);
       
  2332             }
       
  2333         }
       
  2334         sourcetext.clear();
       
  2335         extracomment.clear();
       
  2336         msgid.clear();
       
  2337         extra.clear();
  2255     }
  2338     }
  2256 } break;
  2339 } break;
  2257 
  2340 
  2258 case 70: {
  2341 case 70: {
  2259     sym(1) = QVariantList();
  2342     sym(1) = QVariantList();
  2275     if ((sym(1).type() == QVariant::String) || (sym(3).type() == QVariant::String))
  2358     if ((sym(1).type() == QVariant::String) || (sym(3).type() == QVariant::String))
  2276         sym(1) = sym(1).toString() + sym(3).toString();
  2359         sym(1) = sym(1).toString() + sym(3).toString();
  2277     else
  2360     else
  2278         sym(1) = QVariant();
  2361         sym(1) = QVariant();
  2279 } break;
  2362 } break;
       
  2363 
       
  2364     case 171:
       
  2365 
       
  2366     case 172:
       
  2367 
       
  2368     case 173:
       
  2369 
       
  2370     case 174:
       
  2371 
       
  2372     case 175:
       
  2373 
       
  2374     case 176:
       
  2375 
       
  2376     case 177:
       
  2377 
       
  2378     case 178:
       
  2379 
       
  2380     case 179:
       
  2381 
       
  2382     case 180:
       
  2383 
       
  2384     case 181:
       
  2385 
       
  2386     case 182:
       
  2387 
       
  2388     case 183:
       
  2389 
       
  2390     case 184:
       
  2391 
       
  2392     case 185:
       
  2393     if (!sourcetext.isEmpty() || !extracomment.isEmpty() || !msgid.isEmpty() || !extra.isEmpty()) {
       
  2394         yyMsg() << qPrintable(LU::tr("Discarding unconsumed meta data\n"));
       
  2395         sourcetext.clear();
       
  2396         extracomment.clear();
       
  2397         msgid.clear();
       
  2398         extra.clear();
       
  2399     }
       
  2400     break;
  2280 
  2401 
  2281           } // switch
  2402           } // switch
  2282 
  2403 
  2283           state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
  2404           state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
  2284 
  2405 
  2330               bool first = true;
  2451               bool first = true;
  2331 
  2452 
  2332               for (int s = 0; s < shifts; ++s)
  2453               for (int s = 0; s < shifts; ++s)
  2333                 {
  2454                 {
  2334                   if (first)
  2455                   if (first)
  2335                     error_message += QLatin1String ("Expected ");
  2456                     //: Beginning of the string that contains
       
  2457                     //: comma-separated list of expected tokens
       
  2458                     error_message += LU::tr("Expected ");
  2336                   else
  2459                   else
  2337                     error_message += QLatin1String (", ");
  2460                     error_message += QLatin1String (", ");
  2338 
  2461 
  2339                   first = false;
  2462                   first = false;
  2340                   error_message += QLatin1String("`");
  2463                   error_message += QLatin1String("`");
  2354     }
  2477     }
  2355 
  2478 
  2356     return false;
  2479     return false;
  2357 }
  2480 }
  2358 
  2481 
       
  2482 std::ostream &QScriptParser::yyMsg(int line)
       
  2483 {
       
  2484     return std::cerr << qPrintable(fileName()) << ':' << (line ? line : lexer->startLineNo()) << ": ";
       
  2485 }
       
  2486 
       
  2487 void QScriptParser::processComment(const QChar *chars, int length)
       
  2488 {
       
  2489     if (!length)
       
  2490         return;
       
  2491     // Try to match the logic of the C++ parser.
       
  2492     if (*chars == QLatin1Char(':') && chars[1].isSpace()) {
       
  2493         extracomment += QString(chars+2, length-2);
       
  2494     } else if (*chars == QLatin1Char('=') && chars[1].isSpace()) {
       
  2495         msgid = QString(chars+2, length-2).simplified();
       
  2496     } else if (*chars == QLatin1Char('~') && chars[1].isSpace()) {
       
  2497         QString text = QString(chars+2, length-2).trimmed();
       
  2498         int k = text.indexOf(QLatin1Char(' '));
       
  2499         if (k > -1)
       
  2500             extra.insert(text.left(k), text.mid(k + 1).trimmed());
       
  2501     } else if (*chars == QLatin1Char('%') && chars[1].isSpace()) {
       
  2502         sourcetext.reserve(sourcetext.length() + length-2);
       
  2503         ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length();
       
  2504         int p = 2, c;
       
  2505         forever {
       
  2506             if (p >= length)
       
  2507                 break;
       
  2508             c = chars[p++].unicode();
       
  2509             if (isspace(c))
       
  2510                 continue;
       
  2511             if (c != '"') {
       
  2512                 yyMsg() << qPrintable(LU::tr("Unexpected character in meta string\n"));
       
  2513                 break;
       
  2514             }
       
  2515             forever {
       
  2516                 if (p >= length) {
       
  2517                   whoops:
       
  2518                     yyMsg() << qPrintable(LU::tr("Unterminated meta string\n"));
       
  2519                     break;
       
  2520                 }
       
  2521                 c = chars[p++].unicode();
       
  2522                 if (c == '"')
       
  2523                     break;
       
  2524                 if (c == '\\') {
       
  2525                     if (p >= length)
       
  2526                         goto whoops;
       
  2527                     c = chars[p++].unicode();
       
  2528                     if (c == '\n')
       
  2529                         goto whoops;
       
  2530                     *ptr++ = '\\';
       
  2531                 }
       
  2532                 *ptr++ = c;
       
  2533             }
       
  2534         }
       
  2535         sourcetext.resize(ptr - (ushort *)sourcetext.data());
       
  2536     }
       
  2537 }
       
  2538 
  2359 
  2539 
  2360 bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd)
  2540 bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd)
  2361 {
  2541 {
  2362     QFile file(filename);
  2542     QFile file(filename);
  2363     if (!file.open(QIODevice::ReadOnly)) {
  2543     if (!file.open(QIODevice::ReadOnly)) {
  2364         cd.appendError(QString::fromLatin1("Cannot open %1: %2")
  2544         cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString()));
  2365             .arg(filename, file.errorString()));
       
  2366         return false;
  2545         return false;
  2367     }
  2546     }
  2368     QTextStream ts(&file);
  2547     QTextStream ts(&file);
  2369     QByteArray codecName;
  2548     QByteArray codecName;
  2370     if (!cd.m_codecForSource.isEmpty())
  2549     if (!cd.m_codecForSource.isEmpty())
  2373         codecName = translator.codecName(); // Just because it should be latin1 already
  2552         codecName = translator.codecName(); // Just because it should be latin1 already
  2374     ts.setCodec(QTextCodec::codecForName(codecName));
  2553     ts.setCodec(QTextCodec::codecForName(codecName));
  2375     ts.setAutoDetectUnicode(true);
  2554     ts.setAutoDetectUnicode(true);
  2376 
  2555 
  2377     QString code = ts.readAll();
  2556     QString code = ts.readAll();
  2378     QScript::Lexer lexer;
       
  2379     lexer.setCode(code, /*lineNumber=*/1);
       
  2380     QScriptParser parser;
  2557     QScriptParser parser;
  2381     if (!parser.parse(&lexer, filename, &translator)) {
  2558     QScript::Lexer lexer(&parser);
       
  2559     lexer.setCode(code, filename, /*lineNumber=*/1);
       
  2560     parser.setLexer(&lexer);
       
  2561     if (!parser.parse(&translator)) {
  2382         std::cerr << qPrintable(filename) << ':' << parser.errorLineNumber() << ": "
  2562         std::cerr << qPrintable(filename) << ':' << parser.errorLineNumber() << ": "
  2383                   << qPrintable(parser.errorMessage()) << std::endl;
  2563                   << qPrintable(parser.errorMessage()) << std::endl;
  2384         return false;
  2564         return false;
  2385     }
  2565     }
  2386 
  2566