tools/linguist/lupdate/qscript.g
changeset 37 758a864f9613
parent 33 3e2da88830cd
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
    82 %start Program
    82 %start Program
    83 
    83 
    84 /.
    84 /.
    85 #include <translator.h>
    85 #include <translator.h>
    86 
    86 
       
    87 #include <QtCore/QCoreApplication>
    87 #include <QtCore/qdebug.h>
    88 #include <QtCore/qdebug.h>
    88 #include <QtCore/qnumeric.h>
    89 #include <QtCore/qnumeric.h>
    89 #include <QtCore/qstring.h>
    90 #include <QtCore/qstring.h>
    90 #include <QtCore/qtextcodec.h>
    91 #include <QtCore/qtextcodec.h>
    91 #include <QtCore/qvariant.h>
    92 #include <QtCore/qvariant.h>
    97 #include <stdio.h>
    98 #include <stdio.h>
    98 #include <string.h>
    99 #include <string.h>
    99 
   100 
   100 QT_BEGIN_NAMESPACE
   101 QT_BEGIN_NAMESPACE
   101 
   102 
       
   103 class LU {
       
   104     Q_DECLARE_TR_FUNCTIONS(LUpdate)
       
   105 };
       
   106 
   102 static void recordMessage(
   107 static void recordMessage(
   103     Translator *tor, const QString &context, const QString &text, const QString &comment,
   108     Translator *tor, const QString &context, const QString &text, const QString &comment,
   104     const QString &extracomment, bool plural, const QString &fileName, int lineNo)
   109     const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra,
       
   110     bool plural, const QString &fileName, int lineNo)
   105 {
   111 {
   106     TranslatorMessage msg(
   112     TranslatorMessage msg(
   107         context, text, comment, QString(),
   113         context, text, comment, QString(),
   108         fileName, lineNo, QStringList(),
   114         fileName, lineNo, QStringList(),
   109         TranslatorMessage::Unfinished, plural);
   115         TranslatorMessage::Unfinished, plural);
   110     msg.setExtraComment(extracomment.simplified());
   116     msg.setExtraComment(extracomment.simplified());
       
   117     msg.setId(msgid);
       
   118     msg.setExtras(extra);
   111     tor->extend(msg);
   119     tor->extend(msg);
   112 }
   120 }
   113 
   121 
   114 
   122 
   115 namespace QScript
   123 namespace QScript
   116 {
   124 {
   117 
   125 
       
   126 class CommentProcessor
       
   127 {
       
   128 public:
       
   129     virtual ~CommentProcessor() {}
       
   130     virtual void processComment(const QChar *chars, int length) = 0;
       
   131 };
       
   132 
   118 class Lexer
   133 class Lexer
   119 {
   134 {
   120 public:
   135 public:
   121     Lexer();
   136     Lexer(CommentProcessor *);
   122     ~Lexer();
   137     ~Lexer();
   123 
   138 
   124     void setCode(const QString &c, int lineno);
   139     void setCode(const QString &c, const QString &fileName, int lineno);
   125     int lex();
   140     int lex();
   126 
   141 
       
   142     QString fileName() const { return yyfilename; }
   127     int currentLineNo() const { return yylineno; }
   143     int currentLineNo() const { return yylineno; }
   128     int currentColumnNo() const { return yycolumn; }
   144     int currentColumnNo() const { return yycolumn; }
   129 
   145 
   130     int startLineNo() const { return startlineno; }
   146     int startLineNo() const { return startlineno; }
   131     int startColumnNo() const { return startcolumn; }
   147     int startColumnNo() const { return startcolumn; }
   201         { return err; }
   217         { return err; }
   202     void clearError()
   218     void clearError()
   203         { err = NoError; }
   219         { err = NoError; }
   204 
   220 
   205 private:
   221 private:
       
   222     QString yyfilename;
   206     int yylineno;
   223     int yylineno;
   207     bool done;
   224     bool done;
   208     char *buffer8;
   225     char *buffer8;
   209     QChar *buffer16;
   226     QChar *buffer16;
   210     uint size8, size16;
   227     uint size8, size16;
   254 
   271 
   255     int findReservedWord(const QChar *buffer, int size) const;
   272     int findReservedWord(const QChar *buffer, int size) const;
   256 
   273 
   257     void syncProhibitAutomaticSemicolon();
   274     void syncProhibitAutomaticSemicolon();
   258 
   275 
       
   276     void processComment(const QChar *, int);
       
   277 
   259     const QChar *code;
   278     const QChar *code;
   260     uint length;
   279     uint length;
   261     int yycolumn;
   280     int yycolumn;
   262     int startlineno;
   281     int startlineno;
   263     int startcolumn;
   282     int startcolumn;
   280     bool check_reserved;
   299     bool check_reserved;
   281 
   300 
   282     ParenthesesState parenthesesState;
   301     ParenthesesState parenthesesState;
   283     int parenthesesCount;
   302     int parenthesesCount;
   284     bool prohibitAutomaticSemicolon;
   303     bool prohibitAutomaticSemicolon;
       
   304 
       
   305     CommentProcessor *commentProcessor;
   285 };
   306 };
   286 
   307 
   287 } // namespace QScript
   308 } // namespace QScript
   288 
   309 
   289 extern double qstrtod(const char *s00, char const **se, bool *ok);
   310 extern double qstrtod(const char *s00, char const **se, bool *ok);
   356     return result;
   377     return result;
   357 }
   378 }
   358 
   379 
   359 } // namespace QScript
   380 } // namespace QScript
   360 
   381 
   361 QScript::Lexer::Lexer()
   382 QScript::Lexer::Lexer(QScript::CommentProcessor *proc)
   362     :
   383     :
   363       yylineno(0),
   384       yylineno(0),
   364       size8(128), size16(128), restrKeyword(false),
   385       size8(128), size16(128), restrKeyword(false),
   365       stackToken(-1), pos(0),
   386       stackToken(-1), pos(0),
   366       code(0), length(0),
   387       code(0), length(0),
   367       bol(true),
   388       bol(true),
   368       current(0), next1(0), next2(0), next3(0),
   389       current(0), next1(0), next2(0), next3(0),
   369       err(NoError),
   390       err(NoError),
   370       check_reserved(true),
   391       check_reserved(true),
   371       parenthesesState(IgnoreParentheses),
   392       parenthesesState(IgnoreParentheses),
   372       prohibitAutomaticSemicolon(false)
   393       prohibitAutomaticSemicolon(false),
       
   394       commentProcessor(proc)
   373 {
   395 {
   374     // allocate space for read buffers
   396     // allocate space for read buffers
   375     buffer8 = new char[size8];
   397     buffer8 = new char[size8];
   376     buffer16 = new QChar[size16];
   398     buffer16 = new QChar[size16];
   377     flags = 0;
   399     flags = 0;
   382 {
   404 {
   383     delete [] buffer8;
   405     delete [] buffer8;
   384     delete [] buffer16;
   406     delete [] buffer16;
   385 }
   407 }
   386 
   408 
   387 void QScript::Lexer::setCode(const QString &c, int lineno)
   409 void QScript::Lexer::setCode(const QString &c, const QString &fileName, int lineno)
   388 {
   410 {
   389     errmsg = QString();
   411     errmsg = QString();
       
   412     yyfilename = fileName;
   390     yylineno = lineno;
   413     yylineno = lineno;
   391     yycolumn = 1;
   414     yycolumn = 1;
   392     restrKeyword = false;
   415     restrKeyword = false;
   393     delimited = false;
   416     delimited = false;
   394     stackToken = -1;
   417     stackToken = -1;
   733             if (isWhiteSpace()) {
   756             if (isWhiteSpace()) {
   734                 // do nothing
   757                 // do nothing
   735             } else if (current == '/' && next1 == '/') {
   758             } else if (current == '/' && next1 == '/') {
   736                 recordStartPos();
   759                 recordStartPos();
   737                 shift(1);
   760                 shift(1);
       
   761                 Q_ASSERT(pos16 == 0);
   738                 state = InSingleLineComment;
   762                 state = InSingleLineComment;
   739             } else if (current == '/' && next1 == '*') {
   763             } else if (current == '/' && next1 == '*') {
   740                 recordStartPos();
   764                 recordStartPos();
   741                 shift(1);
   765                 shift(1);
       
   766                 Q_ASSERT(pos16 == 0);
   742                 state = InMultiLineComment;
   767                 state = InMultiLineComment;
   743             } else if (current == 0) {
   768             } else if (current == 0) {
   744                 syncProhibitAutomaticSemicolon();
   769                 syncProhibitAutomaticSemicolon();
   745                 if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
   770                 if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
   746                     // automatic semicolon insertion if program incomplete
   771                     // automatic semicolon insertion if program incomplete
   795                     setDone(Other);
   820                     setDone(Other);
   796                 }
   821                 }
   797                 else {
   822                 else {
   798                     setDone(Bad);
   823                     setDone(Bad);
   799                     err = IllegalCharacter;
   824                     err = IllegalCharacter;
   800                     errmsg = QLatin1String("Illegal character");
   825                     errmsg = LU::tr("Illegal character");
   801                 }
   826                 }
   802             }
   827             }
   803             break;
   828             break;
   804         case InString:
   829         case InString:
   805             if (current == stringType) {
   830             if (current == stringType) {
   806                 shift(1);
   831                 shift(1);
   807                 setDone(String);
   832                 setDone(String);
   808             } else if (current == 0 || isLineTerminator()) {
   833             } else if (current == 0 || isLineTerminator()) {
   809                 setDone(Bad);
   834                 setDone(Bad);
   810                 err = UnclosedStringLiteral;
   835                 err = UnclosedStringLiteral;
   811                 errmsg = QLatin1String("Unclosed string at end of line");
   836                 errmsg = LU::tr("Unclosed string at end of line");
   812             } else if (current == '\\') {
   837             } else if (current == '\\') {
   813                 state = InEscapeSequence;
   838                 state = InEscapeSequence;
   814             } else {
   839             } else {
   815                 record16(current);
   840                 record16(current);
   816             }
   841             }
   832                     record16(convertOctal('0', '0', current));
   857                     record16(convertOctal('0', '0', current));
   833                     state = InString;
   858                     state = InString;
   834                 } else {
   859                 } else {
   835                     setDone(Bad);
   860                     setDone(Bad);
   836                     err = IllegalEscapeSequence;
   861                     err = IllegalEscapeSequence;
   837                     errmsg = QLatin1String("Illegal escape squence");
   862                     errmsg = LU::tr("Illegal escape squence");
   838                 }
   863                 }
   839             } else if (current == 'x')
   864             } else if (current == 'x')
   840                 state = InHexEscape;
   865                 state = InHexEscape;
   841             else if (current == 'u')
   866             else if (current == 'u')
   842                 state = InUnicodeEscape;
   867                 state = InUnicodeEscape;
   871                 shift(1);
   896                 shift(1);
   872                 setDone(String);
   897                 setDone(String);
   873             } else {
   898             } else {
   874                 setDone(Bad);
   899                 setDone(Bad);
   875                 err = IllegalUnicodeEscapeSequence;
   900                 err = IllegalUnicodeEscapeSequence;
   876                 errmsg = QLatin1String("Illegal unicode escape sequence");
   901                 errmsg = LU::tr("Illegal unicode escape sequence");
   877             }
   902             }
   878             break;
   903             break;
   879         case InSingleLineComment:
   904         case InSingleLineComment:
   880             if (isLineTerminator()) {
   905             if (isLineTerminator()) {
       
   906                 record16(current); // include newline
       
   907                 processComment(buffer16, pos16);
   881                 shiftWindowsLineBreak();
   908                 shiftWindowsLineBreak();
   882                 yylineno++;
   909                 yylineno++;
   883                 yycolumn = 0;
   910                 yycolumn = 0;
       
   911                 pos16 = 0;
   884                 terminator = true;
   912                 terminator = true;
   885                 bol = true;
   913                 bol = true;
   886                 if (restrKeyword) {
   914                 if (restrKeyword) {
   887                     token = QScriptGrammar::T_SEMICOLON;
   915                     token = QScriptGrammar::T_SEMICOLON;
   888                     setDone(Other);
   916                     setDone(Other);
   889                 } else
   917                 } else
   890                     state = Start;
   918                     state = Start;
   891             } else if (current == 0) {
   919             } else if (current == 0) {
   892                 setDone(Eof);
   920                 setDone(Eof);
       
   921             } else {
       
   922                 record16(current);
   893             }
   923             }
   894             break;
   924             break;
   895         case InMultiLineComment:
   925         case InMultiLineComment:
   896             if (current == 0) {
   926             if (current == 0) {
   897                 setDone(Bad);
   927                 setDone(Bad);
   898                 err = UnclosedComment;
   928                 err = UnclosedComment;
   899                 errmsg = QLatin1String("Unclosed comment at end of file");
   929                 errmsg = LU::tr("Unclosed comment at end of file");
   900             } else if (isLineTerminator()) {
   930             } else if (isLineTerminator()) {
   901                 shiftWindowsLineBreak();
   931                 shiftWindowsLineBreak();
   902                 yylineno++;
   932                 yylineno++;
   903             } else if (current == '*' && next1 == '/') {
   933             } else if (current == '*' && next1 == '/') {
       
   934                 processComment(buffer16, pos16);
       
   935                 pos16 = 0;
   904                 state = Start;
   936                 state = Start;
   905                 shift(1);
   937                 shift(1);
       
   938             } else {
       
   939                 record16(current);
   906             }
   940             }
   907             break;
   941             break;
   908         case InIdentifier:
   942         case InIdentifier:
   909             if (isIdentLetter(current) || isDecimalDigit(current)) {
   943             if (isIdentLetter(current) || isDecimalDigit(current)) {
   910                 record16(current);
   944                 record16(current);
   978                 record8(current);
  1012                 record8(current);
   979                 state = InExponent;
  1013                 state = InExponent;
   980             } else {
  1014             } else {
   981                 setDone(Bad);
  1015                 setDone(Bad);
   982                 err = IllegalExponentIndicator;
  1016                 err = IllegalExponentIndicator;
   983                 errmsg = QLatin1String("Illegal syntax for exponential number");
  1017                 errmsg = LU::tr("Illegal syntax for exponential number");
   984             }
  1018             }
   985             break;
  1019             break;
   986         case InExponent:
  1020         case InExponent:
   987             if (isDecimalDigit(current)) {
  1021             if (isDecimalDigit(current)) {
   988                 record8(current);
  1022                 record8(current);
  1004     // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
  1038     // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
  1005     if ((state == Number || state == Octal || state == Hex)
  1039     if ((state == Number || state == Octal || state == Hex)
  1006          && isIdentLetter(current)) {
  1040          && isIdentLetter(current)) {
  1007         state = Bad;
  1041         state = Bad;
  1008         err = IllegalIdentifier;
  1042         err = IllegalIdentifier;
  1009         errmsg = QLatin1String("Identifier cannot start with numeric literal");
  1043         errmsg = LU::tr("Identifier cannot start with numeric literal");
  1010     }
  1044     }
  1011 
  1045 
  1012     // terminate string
  1046     // terminate string
  1013     buffer8[pos8] = '\0';
  1047     buffer8[pos8] = '\0';
  1014 
  1048 
  1323     if (prefix == EqualPrefix)
  1357     if (prefix == EqualPrefix)
  1324         record16(QLatin1Char('='));
  1358         record16(QLatin1Char('='));
  1325 
  1359 
  1326     while (1) {
  1360     while (1) {
  1327         if (isLineTerminator() || current == 0) {
  1361         if (isLineTerminator() || current == 0) {
  1328             errmsg = QLatin1String("Unterminated regular expression literal");
  1362             errmsg = LU::tr("Unterminated regular expression literal");
  1329             return false;
  1363             return false;
  1330         }
  1364         }
  1331         else if (current != '/' || lastWasEscape == true)
  1365         else if (current != '/' || lastWasEscape == true)
  1332             {
  1366             {
  1333                 record16(current);
  1367                 record16(current);
  1362     } else {
  1396     } else {
  1363         prohibitAutomaticSemicolon = false;
  1397         prohibitAutomaticSemicolon = false;
  1364     }
  1398     }
  1365 }
  1399 }
  1366 
  1400 
       
  1401 void QScript::Lexer::processComment(const QChar *chars, int length)
       
  1402 {
       
  1403     commentProcessor->processComment(chars, length);
       
  1404 }
       
  1405 
  1367 
  1406 
  1368 class Translator;
  1407 class Translator;
  1369 
  1408 
  1370 class QScriptParser: protected $table
  1409 class QScriptParser: protected $table, public QScript::CommentProcessor
  1371 {
  1410 {
  1372 public:
  1411 public:
  1373     QVariant val;
  1412     QVariant val;
  1374 
  1413 
  1375     struct Location {
  1414     struct Location {
  1381 
  1420 
  1382 public:
  1421 public:
  1383     QScriptParser();
  1422     QScriptParser();
  1384     ~QScriptParser();
  1423     ~QScriptParser();
  1385 
  1424 
  1386     bool parse(QScript::Lexer *lexer,
  1425     void setLexer(QScript::Lexer *);
  1387                const QString &fileName,
  1426 
  1388                Translator *translator);
  1427     bool parse(Translator *translator);
  1389 
  1428 
       
  1429     QString fileName() const
       
  1430     { return lexer->fileName(); }
  1390     inline QString errorMessage() const
  1431     inline QString errorMessage() const
  1391     { return error_message; }
  1432     { return error_message; }
  1392     inline int errorLineNumber() const
  1433     inline int errorLineNumber() const
  1393     { return error_lineno; }
  1434     { return error_lineno; }
  1394     inline int errorColumnNumber() const
  1435     inline int errorColumnNumber() const
  1400     inline QVariant &sym(int index)
  1441     inline QVariant &sym(int index)
  1401     { return sym_stack [tos + index - 1]; }
  1442     { return sym_stack [tos + index - 1]; }
  1402 
  1443 
  1403     inline Location &loc(int index)
  1444     inline Location &loc(int index)
  1404     { return location_stack [tos + index - 2]; }
  1445     { return location_stack [tos + index - 2]; }
       
  1446 
       
  1447     std::ostream &yyMsg(int line = 0);
       
  1448 
       
  1449     virtual void processComment(const QChar *, int);
  1405 
  1450 
  1406 protected:
  1451 protected:
  1407     int tos;
  1452     int tos;
  1408     int stack_size;
  1453     int stack_size;
  1409     QVector<QVariant> sym_stack;
  1454     QVector<QVariant> sym_stack;
  1410     int *state_stack;
  1455     int *state_stack;
  1411     Location *location_stack;
  1456     Location *location_stack;
  1412     QString error_message;
  1457     QString error_message;
  1413     int error_lineno;
  1458     int error_lineno;
  1414     int error_column;
  1459     int error_column;
       
  1460 
       
  1461 private:
       
  1462     QScript::Lexer *lexer;
       
  1463     QString extracomment;
       
  1464     QString msgid;
       
  1465     QString sourcetext;
       
  1466     TranslatorMessage::ExtraData extra;
  1415 };
  1467 };
  1416 
  1468 
  1417 inline void QScriptParser::reallocateStack()
  1469 inline void QScriptParser::reallocateStack()
  1418 {
  1470 {
  1419     if (! stack_size)
  1471     if (! stack_size)
  1436 QScriptParser::QScriptParser():
  1488 QScriptParser::QScriptParser():
  1437     tos(0),
  1489     tos(0),
  1438     stack_size(0),
  1490     stack_size(0),
  1439     sym_stack(0),
  1491     sym_stack(0),
  1440     state_stack(0),
  1492     state_stack(0),
  1441     location_stack(0)
  1493     location_stack(0),
       
  1494     lexer(0)
  1442 {
  1495 {
  1443 }
  1496 }
  1444 
  1497 
  1445 QScriptParser::~QScriptParser()
  1498 QScriptParser::~QScriptParser()
  1446 {
  1499 {
  1458     loc.endLine = lexer->endLineNo();
  1511     loc.endLine = lexer->endLineNo();
  1459     loc.endColumn = lexer->endColumnNo();
  1512     loc.endColumn = lexer->endColumnNo();
  1460     return loc;
  1513     return loc;
  1461 }
  1514 }
  1462 
  1515 
  1463 bool QScriptParser::parse(QScript::Lexer *lexer,
  1516 void QScriptParser::setLexer(QScript::Lexer *lex)
  1464                     const QString &fileName,
  1517 {
  1465      	            Translator *translator)
  1518     lexer = lex;
  1466 {
  1519 }
       
  1520 
       
  1521 bool QScriptParser::parse(Translator *translator)
       
  1522 {
       
  1523   Q_ASSERT(lexer != 0);
  1467   const int INITIAL_STATE = 0;
  1524   const int INITIAL_STATE = 0;
  1468 
  1525 
  1469   int yytoken = -1;
  1526   int yytoken = -1;
  1470   int saved_yytoken = -1;
  1527   int saved_yytoken = -1;
  1471   int identLineNo = -1;
  1528   int identLineNo = -1;
  1628 CallExpression: MemberExpression Arguments ;
  1685 CallExpression: MemberExpression Arguments ;
  1629 /.
  1686 /.
  1630 case $rule_number: {
  1687 case $rule_number: {
  1631     QString name = sym(1).toString();
  1688     QString name = sym(1).toString();
  1632     if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) {
  1689     if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) {
       
  1690         if (!sourcetext.isEmpty())
       
  1691             yyMsg(identLineNo) << qPrintable(LU::tr("//% cannot be used with %1(). Ignoring\n").arg(name));
  1633         QVariantList args = sym(2).toList();
  1692         QVariantList args = sym(2).toList();
  1634         if (args.size() < 2) {
  1693         if (args.size() < 2) {
  1635             std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  1694             yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least two arguments.\n").arg(name));
  1636                       << qPrintable(name) << "() requires at least two arguments.\n";
       
  1637         } else {
  1695         } else {
  1638             if ((args.at(0).type() != QVariant::String)
  1696             if ((args.at(0).type() != QVariant::String)
  1639                 || (args.at(1).type() != QVariant::String)) {
  1697                 || (args.at(1).type() != QVariant::String)) {
  1640                 std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  1698                 yyMsg(identLineNo) << qPrintable(LU::tr("%1(): both arguments must be literal strings.\n").arg(name));
  1641                           << qPrintable(name) << "(): both arguments must be literal strings.\n";
       
  1642             } else {
  1699             } else {
  1643                 QString context = args.at(0).toString();
  1700                 QString context = args.at(0).toString();
  1644                 QString text = args.at(1).toString();
  1701                 QString text = args.at(1).toString();
  1645                 QString comment = args.value(2).toString();
  1702                 QString comment = args.value(2).toString();
  1646                 QString extracomment;
       
  1647                 bool plural = (args.size() > 4);
  1703                 bool plural = (args.size() > 4);
  1648                 recordMessage(translator, context, text, comment, extracomment,
  1704                 recordMessage(translator, context, text, comment, extracomment,
  1649                               plural, fileName, identLineNo);
  1705                               msgid, extra, plural, fileName(), identLineNo);
  1650             }
  1706             }
  1651         }
  1707         }
       
  1708         sourcetext.clear();
       
  1709         extracomment.clear();
       
  1710         msgid.clear();
       
  1711         extra.clear();
  1652     } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) {
  1712     } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) {
       
  1713         if (!sourcetext.isEmpty())
       
  1714             yyMsg(identLineNo) << qPrintable(LU::tr("//% cannot be used with %1(). Ignoring\n").arg(name));
  1653         QVariantList args = sym(2).toList();
  1715         QVariantList args = sym(2).toList();
  1654         if (args.size() < 1) {
  1716         if (args.size() < 1) {
  1655             std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  1717             yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least one argument.\n").arg(name));
  1656                       << qPrintable(name) << "() requires at least one argument.\n";
       
  1657         } else {
  1718         } else {
  1658             if (args.at(0).type() != QVariant::String) {
  1719             if (args.at(0).type() != QVariant::String) {
  1659                 std::cerr << qPrintable(fileName) << ':' << identLineNo << ": "
  1720                 yyMsg(identLineNo) << qPrintable(LU::tr("%1(): text to translate must be a literal string.\n").arg(name));
  1660                           << qPrintable(name) << "(): text to translate must be a literal string.\n";
       
  1661             } else {
  1721             } else {
  1662                 QString context = QFileInfo(fileName).baseName();
  1722                 QString context = QFileInfo(fileName()).baseName();
  1663                 QString text = args.at(0).toString();
  1723                 QString text = args.at(0).toString();
  1664                 QString comment = args.value(1).toString();
  1724                 QString comment = args.value(1).toString();
  1665                 QString extracomment;
       
  1666                 bool plural = (args.size() > 2);
  1725                 bool plural = (args.size() > 2);
  1667                 recordMessage(translator, context, text, comment, extracomment,
  1726                 recordMessage(translator, context, text, comment, extracomment,
  1668                               plural, fileName, identLineNo);
  1727                               msgid, extra, plural, fileName(), identLineNo);
  1669             }
  1728             }
  1670         }
  1729         }
       
  1730         sourcetext.clear();
       
  1731         extracomment.clear();
       
  1732         msgid.clear();
       
  1733         extra.clear();
       
  1734     } else if ((name == QLatin1String("qsTrId")) || (name == QLatin1String("QT_TRID_NOOP"))) {
       
  1735         if (!msgid.isEmpty())
       
  1736             yyMsg(identLineNo) << qPrintable(LU::tr("//= cannot be used with %1(). Ignoring\n").arg(name));
       
  1737         QVariantList args = sym(2).toList();
       
  1738         if (args.size() < 1) {
       
  1739             yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least one argument.\n").arg(name));
       
  1740         } else {
       
  1741             if (args.at(0).type() != QVariant::String) {
       
  1742                 yyMsg(identLineNo) << qPrintable(LU::tr("%1(): identifier must be a literal string.\n").arg(name));
       
  1743             } else {
       
  1744                 msgid = args.at(0).toString();
       
  1745                 bool plural = (args.size() > 1);
       
  1746                 recordMessage(translator, QString(), sourcetext, QString(), extracomment,
       
  1747                               msgid, extra, plural, fileName(), identLineNo);
       
  1748             }
       
  1749         }
       
  1750         sourcetext.clear();
       
  1751         extracomment.clear();
       
  1752         msgid.clear();
       
  1753         extra.clear();
  1671     }
  1754     }
  1672 } break;
  1755 } break;
  1673 ./
  1756 ./
  1674 
  1757 
  1675 CallExpression: CallExpression Arguments ;
  1758 CallExpression: CallExpression Arguments ;
  1811 ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
  1894 ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
  1812 ExpressionNotInOpt: ;
  1895 ExpressionNotInOpt: ;
  1813 ExpressionNotInOpt: ExpressionNotIn ;
  1896 ExpressionNotInOpt: ExpressionNotIn ;
  1814 
  1897 
  1815 Statement: Block ;
  1898 Statement: Block ;
       
  1899 /.
       
  1900     case $rule_number:
       
  1901 ./
  1816 Statement: VariableStatement ;
  1902 Statement: VariableStatement ;
       
  1903 /.
       
  1904     case $rule_number:
       
  1905 ./
  1817 Statement: EmptyStatement ;
  1906 Statement: EmptyStatement ;
       
  1907 /.
       
  1908     case $rule_number:
       
  1909 ./
  1818 Statement: ExpressionStatement ;
  1910 Statement: ExpressionStatement ;
       
  1911 /.
       
  1912     case $rule_number:
       
  1913 ./
  1819 Statement: IfStatement ;
  1914 Statement: IfStatement ;
       
  1915 /.
       
  1916     case $rule_number:
       
  1917 ./
  1820 Statement: IterationStatement ;
  1918 Statement: IterationStatement ;
       
  1919 /.
       
  1920     case $rule_number:
       
  1921 ./
  1821 Statement: ContinueStatement ;
  1922 Statement: ContinueStatement ;
       
  1923 /.
       
  1924     case $rule_number:
       
  1925 ./
  1822 Statement: BreakStatement ;
  1926 Statement: BreakStatement ;
       
  1927 /.
       
  1928     case $rule_number:
       
  1929 ./
  1823 Statement: ReturnStatement ;
  1930 Statement: ReturnStatement ;
       
  1931 /.
       
  1932     case $rule_number:
       
  1933 ./
  1824 Statement: WithStatement ;
  1934 Statement: WithStatement ;
       
  1935 /.
       
  1936     case $rule_number:
       
  1937 ./
  1825 Statement: LabelledStatement ;
  1938 Statement: LabelledStatement ;
       
  1939 /.
       
  1940     case $rule_number:
       
  1941 ./
  1826 Statement: SwitchStatement ;
  1942 Statement: SwitchStatement ;
       
  1943 /.
       
  1944     case $rule_number:
       
  1945 ./
  1827 Statement: ThrowStatement ;
  1946 Statement: ThrowStatement ;
       
  1947 /.
       
  1948     case $rule_number:
       
  1949 ./
  1828 Statement: TryStatement ;
  1950 Statement: TryStatement ;
       
  1951 /.
       
  1952     case $rule_number:
       
  1953 ./
  1829 Statement: DebuggerStatement ;
  1954 Statement: DebuggerStatement ;
       
  1955 /.
       
  1956     case $rule_number:
       
  1957     if (!sourcetext.isEmpty() || !extracomment.isEmpty() || !msgid.isEmpty() || !extra.isEmpty()) {
       
  1958         yyMsg() << qPrintable(LU::tr("Discarding unconsumed meta data\n"));
       
  1959         sourcetext.clear();
       
  1960         extracomment.clear();
       
  1961         msgid.clear();
       
  1962         extra.clear();
       
  1963     }
       
  1964     break;
       
  1965 ./
  1830 
  1966 
  1831 Block: T_LBRACE StatementListOpt T_RBRACE ;
  1967 Block: T_LBRACE StatementListOpt T_RBRACE ;
  1832 StatementList: Statement ;
  1968 StatementList: Statement ;
  1833 StatementList: StatementList Statement ;
  1969 StatementList: StatementList Statement ;
  1834 StatementListOpt: ;
  1970 StatementListOpt: ;
  1963 
  2099 
  1964               for (int s = 0; s < shifts; ++s)
  2100               for (int s = 0; s < shifts; ++s)
  1965                 {
  2101                 {
  1966                   if (first)
  2102                   if (first)
  1967                     error_message += QLatin1String ("Expected ");
  2103                     error_message += QLatin1String ("Expected ");
       
  2104                     //: Beginning of the string that contains
       
  2105                     //: comma-separated list of expected tokens
       
  2106                     error_message += LU::tr("Expected ");
  1968                   else
  2107                   else
  1969                     error_message += QLatin1String (", ");
  2108                     error_message += QLatin1String (", ");
  1970 
  2109 
  1971                   first = false;
  2110                   first = false;
  1972                   error_message += QLatin1String("`");
  2111                   error_message += QLatin1String("`");
  1986     }
  2125     }
  1987 
  2126 
  1988     return false;
  2127     return false;
  1989 }
  2128 }
  1990 
  2129 
       
  2130 std::ostream &QScriptParser::yyMsg(int line)
       
  2131 {
       
  2132     return std::cerr << qPrintable(fileName()) << ':' << (line ? line : lexer->startLineNo()) << ": ";
       
  2133 }
       
  2134 
       
  2135 void QScriptParser::processComment(const QChar *chars, int length)
       
  2136 {
       
  2137     if (!length)
       
  2138         return;
       
  2139     // Try to match the logic of the C++ parser.
       
  2140     if (*chars == QLatin1Char(':') && chars[1].isSpace()) {
       
  2141         extracomment += QString(chars+2, length-2);
       
  2142     } else if (*chars == QLatin1Char('=') && chars[1].isSpace()) {
       
  2143         msgid = QString(chars+2, length-2).simplified();
       
  2144     } else if (*chars == QLatin1Char('~') && chars[1].isSpace()) {
       
  2145         QString text = QString(chars+2, length-2).trimmed();
       
  2146         int k = text.indexOf(QLatin1Char(' '));
       
  2147         if (k > -1)
       
  2148             extra.insert(text.left(k), text.mid(k + 1).trimmed());
       
  2149     } else if (*chars == QLatin1Char('%') && chars[1].isSpace()) {
       
  2150         sourcetext.reserve(sourcetext.length() + length-2);
       
  2151         ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length();
       
  2152         int p = 2, c;
       
  2153         forever {
       
  2154             if (p >= length)
       
  2155                 break;
       
  2156             c = chars[p++].unicode();
       
  2157             if (isspace(c))
       
  2158                 continue;
       
  2159             if (c != '"') {
       
  2160                 yyMsg() << qPrintable(LU::tr("Unexpected character in meta string\n"));
       
  2161                 break;
       
  2162             }
       
  2163             forever {
       
  2164                 if (p >= length) {
       
  2165                   whoops:
       
  2166                     yyMsg() << qPrintable(LU::tr("Unterminated meta string\n"));
       
  2167                     break;
       
  2168                 }
       
  2169                 c = chars[p++].unicode();
       
  2170                 if (c == '"')
       
  2171                     break;
       
  2172                 if (c == '\\') {
       
  2173                     if (p >= length)
       
  2174                         goto whoops;
       
  2175                     c = chars[p++].unicode();
       
  2176                     if (c == '\n')
       
  2177                         goto whoops;
       
  2178                     *ptr++ = '\\';
       
  2179                 }
       
  2180                 *ptr++ = c;
       
  2181             }
       
  2182         }
       
  2183         sourcetext.resize(ptr - (ushort *)sourcetext.data());
       
  2184     }
       
  2185 }
       
  2186 
  1991 
  2187 
  1992 bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd)
  2188 bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd)
  1993 {
  2189 {
  1994     QFile file(filename);
  2190     QFile file(filename);
  1995     if (!file.open(QIODevice::ReadOnly)) {
  2191     if (!file.open(QIODevice::ReadOnly)) {
  1996         cd.appendError(QString::fromLatin1("Cannot open %1: %2")
  2192         cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString()));
  1997             .arg(filename, file.errorString()));
       
  1998         return false;
  2193         return false;
  1999     }
  2194     }
  2000     QTextStream ts(&file);
  2195     QTextStream ts(&file);
  2001     QByteArray codecName;
  2196     QByteArray codecName;
  2002     if (!cd.m_codecForSource.isEmpty())
  2197     if (!cd.m_codecForSource.isEmpty())
  2005         codecName = translator.codecName(); // Just because it should be latin1 already
  2200         codecName = translator.codecName(); // Just because it should be latin1 already
  2006     ts.setCodec(QTextCodec::codecForName(codecName));
  2201     ts.setCodec(QTextCodec::codecForName(codecName));
  2007     ts.setAutoDetectUnicode(true);
  2202     ts.setAutoDetectUnicode(true);
  2008 
  2203 
  2009     QString code = ts.readAll();
  2204     QString code = ts.readAll();
  2010     QScript::Lexer lexer;
       
  2011     lexer.setCode(code, /*lineNumber=*/1);
       
  2012     QScriptParser parser;
  2205     QScriptParser parser;
  2013     if (!parser.parse(&lexer, filename, &translator)) {
  2206     QScript::Lexer lexer(&parser);
       
  2207     lexer.setCode(code, filename, /*lineNumber=*/1);
       
  2208     parser.setLexer(&lexer);
       
  2209     if (!parser.parse(&translator)) {
  2014         std::cerr << qPrintable(filename) << ':' << parser.errorLineNumber() << ": "
  2210         std::cerr << qPrintable(filename) << ':' << parser.errorLineNumber() << ": "
  2015                   << qPrintable(parser.errorMessage()) << std::endl;
  2211                   << qPrintable(parser.errorMessage()) << std::endl;
  2016         return false;
  2212         return false;
  2017     }
  2213     }
  2018 
  2214