Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
java.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include <translator.h>
5
6#include <QtCore/QDebug>
7#include <QtCore/QFile>
8#include <QtCore/QStack>
9#include <QtCore/QStack>
10#include <QtCore/QString>
11#include <QtCore/QCoreApplication>
12#include <QtCore/QStringConverter>
13#include <QtCore/QTextStream>
14
15#include <iostream>
16
17#include <ctype.h>
18
19QT_BEGIN_NAMESPACE
20
21using namespace Qt::Literals::StringLiterals;
22
29
30class Scope
31{
32 public:
34 enum Type {Clazz, Function, Other} type;
35 int line;
36
37 Scope(const QString & name, Type type, int line) :
38 name(name),
39 type(type),
40 line(line)
41 {}
42
44 {}
45};
46
47/*
48 The tokenizer maintains the following global variables. The names
49 should be self-explanatory.
50*/
51
53static QChar yyCh;
57static bool yyEOF = false;
58
60static int yyParenDepth;
61static int yyLineNo;
62static int yyCurLineNo;
63static int yyParenLineNo;
64static int yyTok;
65
66// the string to read from and current position in the string
68static int yyInPos;
69
70// The parser maintains the following global variables.
73
74std::ostream &yyMsg(int line = 0)
75{
76 return std::cerr << qPrintable(yyFileName) << ':' << (line ? line : yyLineNo) << ": ";
77}
78
79static QChar getChar()
80{
81 if (yyInPos >= yyInStr.size()) {
82 yyEOF = true;
83 return QChar();
84 }
85 QChar c = yyInStr[yyInPos++];
86 if (c == u'\n')
88 return c;
89}
90
91static int getToken()
92{
93 const char tab[] = "bfnrt\"\'\\";
94 const char backTab[] = "\b\f\n\r\t\"\'\\";
95
96 yyIdent.clear();
97 yyComment.clear();
98 yyString.clear();
99
100 while (!yyEOF) {
102
103 if ( yyCh.isLetter() || yyCh.toLatin1() == '_' ) {
104 do {
105 yyIdent.append(yyCh);
106 yyCh = getChar();
107 } while ( yyCh.isLetterOrNumber() || yyCh.toLatin1() == '_' );
108
109 if (yyTok != Tok_Dot) {
110 switch ( yyIdent.at(0).toLatin1() ) {
111 case 'r':
112 if (yyIdent == "return"_L1)
113 return Tok_return;
114 break;
115 case 'c':
116 if (yyIdent == "class"_L1)
117 return Tok_class;
118 break;
119 case 'n':
120 if (yyIdent == "null"_L1)
121 return Tok_null;
122 break;
123 }
124 }
125 switch ( yyIdent.at(0).toLatin1() ) {
126 case 'p':
127 if (yyIdent == "package"_L1)
128 return Tok_Package;
129 break;
130 case 't':
131 if (yyIdent == "tr"_L1)
132 return Tok_tr;
133 if (yyIdent == "translate"_L1)
134 return Tok_translate;
135 }
136 return Tok_Ident;
137 } else {
138 switch ( yyCh.toLatin1() ) {
139
140 case '/':
141 yyCh = getChar();
142 if (yyCh == u'/') {
143 do {
144 yyCh = getChar();
145 if (yyEOF)
146 break;
147 yyComment.append(yyCh);
148 } while (yyCh != u'\n');
149 return Tok_Comment;
150
151 } else if (yyCh == u'*') {
152 bool metAster = false;
153 bool metAsterSlash = false;
154
155 while ( !metAsterSlash ) {
156 yyCh = getChar();
157 if (yyEOF) {
158 yyMsg() << "Unterminated Java comment.\n";
159 return Tok_Comment;
160 }
161
162 yyComment.append( yyCh );
163
164 if (yyCh == u'*')
165 metAster = true;
166 else if (metAster && yyCh == u'/')
167 metAsterSlash = true;
168 else
169 metAster = false;
170 }
171 yyComment.chop(2);
172 yyCh = getChar();
173
174 return Tok_Comment;
175 }
176 break;
177 case '"':
178 yyCh = getChar();
179
180 while (!yyEOF && yyCh != u'\n' && yyCh != u'"') {
181
182 if (yyCh == u'\\') {
183 yyCh = getChar();
184 if (yyCh == u'u') {
185 yyCh = getChar();
186 uint unicode(0);
187 for (int i = 4; i > 0; --i) {
188 unicode = unicode << 4;
189 if( yyCh.isDigit() ) {
190 unicode += yyCh.digitValue();
191 }
192 else {
193 int sub(yyCh.toLower().toLatin1() - 87);
194 if( sub > 15 || sub < 10) {
195 yyMsg() << "Invalid Unicode value.\n";
196 break;
197 }
198 unicode += sub;
199 }
200 yyCh = getChar();
201 }
202 yyString.append(QChar(unicode));
203 } else if (yyCh == u'\n') {
204 yyCh = getChar();
205 } else if (const char *p = strchr(tab, yyCh.toLatin1()); p) {
206 yyString.append(QLatin1Char(backTab[p - tab]));
207 yyCh = getChar();
208 } else {
209 yyMsg() << "Invalid escaped character \'\\" << qPrintable(yyCh)
210 << "\'\n";
211 yyCh = getChar();
212 }
213 } else {
214 yyString.append(yyCh);
215 yyCh = getChar();
216 }
217 }
218
219 if (yyCh != u'"')
220 yyMsg() << "Unterminated string.\n";
221
222 yyCh = getChar();
223
224 return Tok_String;
225
226 case ':':
227 yyCh = getChar();
228 return Tok_Colon;
229 case '\'':
230 yyCh = getChar();
231
232 if (yyCh == u'\\')
233 yyCh = getChar();
234 do {
235 yyCh = getChar();
236 } while (!yyEOF && yyCh != u'\'');
237 yyCh = getChar();
238 break;
239 case '{':
240 yyCh = getChar();
241 return Tok_LeftBrace;
242 case '}':
243 yyCh = getChar();
244 return Tok_RightBrace;
245 case '(':
246 if (yyParenDepth == 0)
248 yyParenDepth++;
249 yyCh = getChar();
250 return Tok_LeftParen;
251 case ')':
252 if (yyParenDepth == 0)
254 yyParenDepth--;
255 yyCh = getChar();
256 return Tok_RightParen;
257 case ',':
258 yyCh = getChar();
259 return Tok_Comma;
260 case '.':
261 yyCh = getChar();
262 return Tok_Dot;
263 case ';':
264 yyCh = getChar();
265 return Tok_Semicolon;
266 case '+':
267 yyCh = getChar();
268 if (yyCh == u'+') {
269 yyCh = getChar();
270 return Tok_PlusPlus;
271 }
272 if (yyCh == u'=') {
273 yyCh = getChar();
274 return Tok_PlusEq;
275 }
276 return Tok_Plus;
277 case '0':
278 case '1':
279 case '2':
280 case '3':
281 case '4':
282 case '5':
283 case '6':
284 case '7':
285 case '8':
286 case '9':
287 {
288 QByteArray ba;
289 ba += yyCh.toLatin1();
290 yyCh = getChar();
291 bool hex = yyCh == u'x';
292 if ( hex ) {
293 ba += yyCh.toLatin1();
294 yyCh = getChar();
295 }
296 while ( hex ? isxdigit(yyCh.toLatin1()) : yyCh.isDigit() ) {
297 ba += yyCh.toLatin1();
298 yyCh = getChar();
299 }
300 bool ok;
301 yyInteger = ba.toLongLong(&ok);
302 if (ok) return Tok_Integer;
303 break;
304 }
305 default:
306 yyCh = getChar();
307 }
308 }
309 }
310 return Tok_Eof;
311}
312
313static bool match( int t )
314{
315 bool matches = ( yyTok == t );
316 if ( matches )
318 return matches;
319}
320
321static bool matchString( QString &s )
322{
323 if ( yyTok != Tok_String )
324 return false;
325
326 s = yyString;
328 while ( yyTok == Tok_Plus ) {
330 if (yyTok == Tok_String)
331 s += yyString;
332 else {
333 yyMsg() <<
334 "String used in translation can contain only literals"
335 " concatenated with other literals, not expressions or numbers.\n";
336 return false;
337 }
339 }
340 return true;
341}
342
343static bool matchStringOrNull(QString &s)
344{
345 bool matches = matchString(s);
346 if (!matches) {
347 matches = (yyTok == Tok_null);
348 if (matches)
350 }
351 return matches;
352}
353
354/*
355 * match any expression that can return a number, which can be
356 * 1. Literal number (e.g. '11')
357 * 2. simple identifier (e.g. 'm_count')
358 * 3. simple function call (e.g. 'size()' )
359 * 4. function call on an object (e.g. 'list.size()')
360 * 5. function call on an object (e.g. 'list->size()')
361 *
362 * Other cases:
363 * size(2,4)
364 * list().size()
365 * list(a,b).size(2,4)
366 * etc...
367 */
368static bool matchExpression()
369{
370 if (match(Tok_Integer)) {
371 return true;
372 }
373
374 int parenlevel = 0;
375 while (match(Tok_Ident) || parenlevel > 0) {
376 if (yyTok == Tok_RightParen) {
377 if (parenlevel == 0) break;
378 --parenlevel;
380 } else if (yyTok == Tok_LeftParen) {
382 if (yyTok == Tok_RightParen) {
384 } else {
385 ++parenlevel;
386 }
387 } else if (yyTok == Tok_Ident) {
388 continue;
389 } else if (parenlevel == 0) {
390 return false;
391 }
392 }
393 return true;
394}
395
396static const QString context()
397{
398 QString context(yyPackage);
399 bool innerClass = false;
400 for (int i = 0; i < yyScope.size(); ++i) {
401 if (yyScope.at(i)->type == Scope::Clazz) {
402 if (innerClass)
403 context.append("$"_L1);
404 else
405 context.append("."_L1);
406
407 context.append(yyScope.at(i)->name);
408 innerClass = true;
409 }
410 }
411 return context;
412}
413
414static void recordMessage(
415 Translator *tor, const QString &context, const QString &text, const QString &comment,
416 const QString &extracomment, bool plural, ConversionData &cd)
417{
419 context, text, comment, QString(),
420 yyFileName, yyLineNo, QStringList(),
422 msg.setExtraComment(extracomment.simplified());
423 tor->extend(msg, cd);
424}
425
426static void parse(Translator *tor, ConversionData &cd)
427{
428 QString text;
429 QString com;
430 QString extracomment;
431
432 yyEOF = false;
433 yyCh = getChar();
434
436 while ( yyTok != Tok_Eof ) {
437 switch ( yyTok ) {
438 case Tok_class:
440 if(yyTok == Tok_Ident) {
441 yyScope.push(new Scope(yyIdent, Scope::Clazz, yyLineNo));
442 }
443 else {
444 yyMsg() << "'class' must be followed by a class name.\n";
445 break;
446 }
447 while (!match(Tok_LeftBrace)) {
449 }
450 break;
451
452 case Tok_tr:
454 if ( match(Tok_LeftParen) && matchString(text) ) {
455 com.clear();
456 bool plural = false;
457
458 if ( match(Tok_RightParen) ) {
459 // no comment
460 } else if (match(Tok_Comma) && matchStringOrNull(com)) { //comment
462 // ok,
463 } else if (match(Tok_Comma)) {
464 plural = true;
465 }
466 }
467 recordMessage(tor, context(), text, com, extracomment, plural, cd);
468 }
469 break;
470 case Tok_translate:
471 {
472 QString contextOverride;
474 if ( match(Tok_LeftParen) &&
475 matchString(contextOverride) &&
476 match(Tok_Comma) &&
477 matchString(text) ) {
478
479 com.clear();
480 bool plural = false;
482 // look for comment
483 if ( match(Tok_Comma) && matchStringOrNull(com)) {
486 plural = true;
487 } else {
488 break;
489 }
490 }
491 } else {
492 break;
493 }
494 }
495 recordMessage(tor, contextOverride, text, com, extracomment, plural, cd);
496 }
497 }
498 break;
499
500 case Tok_Ident:
502 break;
503
504 case Tok_Comment:
505 if (yyComment.startsWith(u':')) {
506 yyComment.remove(0, 1);
507 extracomment.append(yyComment);
508 }
510 break;
511
512 case Tok_RightBrace:
513 if ( yyScope.isEmpty() ) {
514 yyMsg() << "Excess closing brace.\n";
515 }
516 else
517 delete (yyScope.pop());
518 extracomment.clear();
520 break;
521
522 case Tok_LeftBrace:
523 yyScope.push(new Scope(QString(), Scope::Other, yyLineNo));
525 break;
526
527 case Tok_Semicolon:
528 extracomment.clear();
530 break;
531
532 case Tok_Package:
534 while(!match(Tok_Semicolon)) {
535 switch(yyTok) {
536 case Tok_Ident:
537 yyPackage.append(yyIdent);
538 break;
539 case Tok_Dot:
540 yyPackage.append("."_L1);
541 break;
542 default:
543 yyMsg() << "'package' must be followed by package name.\n";
544 break;
545 }
547 }
548 break;
549
550 default:
552 }
553 }
554
555 if ( !yyScope.isEmpty() )
556 yyMsg(yyScope.top()->line) << "Unbalanced opening brace.\n";
557 else if ( yyParenDepth != 0 )
558 yyMsg(yyParenLineNo) << "Unbalanced opening parenthesis.\n";
559}
560
561
562bool loadJava(Translator &translator, const QString &filename, ConversionData &cd)
563{
564 QFile file(filename);
565 if (!file.open(QIODevice::ReadOnly)) {
566 cd.appendError(QStringLiteral("Cannot open %1: %2").arg(filename, file.errorString()));
567 return false;
568 }
569
570 yyInPos = -1;
571 yyFileName = filename;
572 yyPackage.clear();
573 yyScope.clear();
574 yyTok = -1;
575 yyParenDepth = 0;
576 yyCurLineNo = 0;
577 yyParenLineNo = 1;
578
579 QTextStream ts(&file);
580 ts.setEncoding(cd.m_sourceIsUtf16 ? QStringConverter::Utf16 : QStringConverter::Utf8);
581 ts.setAutoDetectUnicode(true);
582 yyInStr = ts.readAll();
583 yyInPos = 0;
584 yyFileName = filename;
585 yyCurLineNo = 1;
586 yyParenLineNo = 1;
587
588 parse(&translator, cd);
589 return true;
590}
591
592QT_END_NAMESPACE
Definition java.cpp:31
int line
Definition java.cpp:35
QString name
Definition java.cpp:33
Type
Definition java.cpp:34
@ Clazz
Definition java.cpp:34
@ Function
Definition java.cpp:34
@ Other
Definition java.cpp:34
Scope(const QString &name, Type type, int line)
Definition java.cpp:37
~Scope()
Definition java.cpp:43
void extend(const TranslatorMessage &msg, ConversionData &cd)
std::ostream & yyMsg(int line=0)
Definition java.cpp:74
static bool yyEOF
Definition java.cpp:57
static int yyTok
Definition java.cpp:64
static int yyLineNo
Definition java.cpp:61
static QChar yyCh
Definition java.cpp:53
static bool match(int t)
Definition java.cpp:313
static int yyInPos
Definition java.cpp:68
static bool matchString(QString &s)
Definition java.cpp:321
static QString yyComment
Definition java.cpp:55
static int yyCurLineNo
Definition java.cpp:62
static int getToken()
Definition java.cpp:91
static QChar getChar()
Definition java.cpp:79
static bool matchExpression()
Definition java.cpp:368
static QString yyString
Definition java.cpp:56
static QString yyIdent
Definition java.cpp:54
static QString yyInStr
Definition java.cpp:67
@ Tok_Comment
Definition java.cpp:25
@ Tok_Ident
Definition java.cpp:24
@ Tok_return
Definition java.cpp:23
@ Tok_Eof
Definition java.cpp:23
@ Tok_PlusEq
Definition java.cpp:28
@ Tok_String
Definition java.cpp:25
@ Tok_LeftBrace
Definition java.cpp:26
@ Tok_PlusPlus
Definition java.cpp:28
@ Tok_Colon
Definition java.cpp:25
@ Tok_Plus
Definition java.cpp:28
@ Tok_Semicolon
Definition java.cpp:27
@ Tok_LeftParen
Definition java.cpp:26
@ Tok_tr
Definition java.cpp:23
@ Tok_translate
Definition java.cpp:24
@ Tok_Comma
Definition java.cpp:27
@ Tok_class
Definition java.cpp:23
@ Tok_Package
Definition java.cpp:24
@ Tok_Integer
Definition java.cpp:28
@ Tok_RightParen
Definition java.cpp:27
@ Tok_null
Definition java.cpp:28
@ Tok_RightBrace
Definition java.cpp:26
@ Tok_Dot
Definition java.cpp:25
static void parse(Translator *tor, ConversionData &cd)
Definition java.cpp:426
static QString yyFileName
Definition java.cpp:52
static QStack< Scope * > yyScope
Definition java.cpp:72
static bool matchStringOrNull(QString &s)
Definition java.cpp:343
static const QString context()
Definition java.cpp:396
static QString yyPackage
Definition java.cpp:71
static void recordMessage(Translator *tor, const QString &context, const QString &text, const QString &comment, const QString &extracomment, bool plural, ConversionData &cd)
Definition java.cpp:414
static qlonglong yyInteger
Definition java.cpp:59
static int yyParenDepth
Definition java.cpp:60
static int yyParenLineNo
Definition java.cpp:63
bool loadJava(Translator &translator, const QString &filename, ConversionData &cd)
Definition java.cpp:562