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; } |
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; |
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); |
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: ; |
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 |