1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the tools applications of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
47 #include "cpptoqsconverter.h"
51 #define CONFIG_QUICK "quick"
52 #define CONFIG_INDENTSIZE "indentsize"
54 void setTabSize( int size
);
55 void setIndentSize( int size
);
56 int columnForIndex( const QString
& t
, int index
);
57 int indentForBottomLine( const QStringList
& program
, QChar typedIn
);
59 static QString balancedParens
= "(?:[^()]+|\\([^()]*\\))*";
61 QRegExp
CppToQsConverter::qClassRegExp
;
62 QRegExp
CppToQsConverter::addressOperatorRegExp
;
63 QRegExp
CppToQsConverter::gulbrandsenRegExp
;
64 int CppToQsConverter::tabSize
;
66 ClassNode
*CppToQsConverter::findClassNode( Tree
*qsTree
,
67 const QString
& qtName
)
69 ClassNode
*classe
= (ClassNode
*) qsTree
->findNode( QStringList(qtName
), Node::Class
);
71 classe
= (ClassNode
*) qsTree
->findNode( QStringList(qtName
.mid(1)), Node::Class
);
75 QString
CppToQsConverter::convertedDataType( Tree
*qsTree
,
76 const QString
& leftType
,
77 const QString
& /* rightType */ )
81 if ( s
.startsWith("const ") )
83 while ( s
.endsWith("*") || s
.endsWith("&") || s
.endsWith(" ") )
84 s
.truncate( s
.length() - 1 );
86 switch ( s
[0].unicode() ) {
88 if ( s
== "QCString" ) {
91 Node
*node
= findClassNode( qsTree
, s
);
105 if ( leftType
== "const char *" ) {
124 if ( s
== "long" || s
== "long int" || s
== "long long" ||
125 s
== "long long int" || s
== "long double" )
129 if ( s
== "short" || s
== "short int" || s
== "signed char" ||
130 s
== "signed short" || s
== "signed short int" || s
== "signed" ||
131 s
== "signed int" || s
== "signed long" || s
== "signed long int" )
135 if ( s
== "uchar" || s
== "unsigned" || s
== "unsigned char" ||
136 s
== "ushort" || s
== "unsigned short" ||
137 s
== "unsigned short int" || s
== "uint" || s
== "unsigned int" ||
138 s
== "ulong" || s
== "unsigned long" || s
== "unsigned long int" )
148 QString
CppToQsConverter::convertedCode( Tree
*qsTree
, const QString
& code
,
149 const QSet
<QString
>& classesWithNoQ
)
153 QStringList comments
;
154 int programWidth
= 0;
156 QStringList originalLines
= code
.split("\n");
157 QStringList::ConstIterator ol
= originalLines
.begin();
158 while ( ol
!= originalLines
.end() ) {
159 QString code
= (*ol
).trimmed();
162 int slashSlash
= code
.indexOf( "//" );
163 if ( slashSlash
!= -1 ) {
164 comment
= code
.mid( slashSlash
);
165 code
.truncate( slashSlash
);
166 code
= code
.trimmed();
169 code
= convertCodeLine( qsTree
, program
, code
, classesWithNoQ
);
170 program
.append( code
);
172 comment
= convertComment( qsTree
, comment
, classesWithNoQ
);
173 comments
.append( comment
);
175 int n
= indentForBottomLine( program
, QChar::Null
);
176 for ( int i
= 0; i
< n
; i
++ )
177 program
.last().prepend( " " );
179 int width
= columnForIndex( program
.last(), program
.last().length() );
180 if ( !comment
.isEmpty() && width
> programWidth
)
181 programWidth
= width
;
185 programWidth
= ( (programWidth
+ (tabSize
- 1) + 2) / tabSize
) * tabSize
;
187 QStringList::ConstIterator p
= program
.begin();
188 QStringList::ConstIterator c
= comments
.begin();
189 while ( c
!= comments
.end() ) {
190 if ( c
!= comments
.begin() )
193 if ( (*p
).trimmed().isEmpty() ) {
194 if ( !(*c
).isEmpty() )
198 if ( !(*c
).isEmpty() ) {
199 int i
= columnForIndex( *p
, (*p
).length() );
200 while ( i
++ < programWidth
)
211 void CppToQsConverter::initialize( const Config
& config
)
213 qClassRegExp
.setPattern( "\\bQ([A-Z][A-Za-z]+)\\b" );
214 addressOperatorRegExp
.setPattern( "([(\\s])[*&]([a-zA-Z])" );
215 gulbrandsenRegExp
.setPattern( "\\b::\\b|->" );
217 tabSize
= config
.getInt( CONFIG_TABSIZE
);
218 setTabSize( tabSize
);
220 int size
= config
.getInt( CONFIG_QUICK
+ Config::dot
+ CONFIG_INDENTSIZE
);
222 setIndentSize( size
);
225 void CppToQsConverter::terminate()
229 QString
CppToQsConverter::convertCodeLine( Tree
*qsTree
,
230 const QStringList
& program
,
232 const QSet
<QString
>& classesWithNoQ
)
234 static QString dataTypeFmt
=
235 "(?!return)(?:const\\b\\s*)?[A-Za-z_]+(?:\\s*[*&])?";
236 static QRegExp
funcPrototypeRegExp(
237 "(" + dataTypeFmt
+ ")\\s*\\b([A-Z][a-zA-Z_0-9]*::)?"
238 "([a-z][a-zA-Z_0-9]*)\\(([^);]*)(\\)?)(?:\\s*const)?" );
239 static QRegExp
paramRegExp(
240 "^\\s*(" + dataTypeFmt
+ ")\\s*\\b([a-z][a-zA-Z_0-9]*)\\s*(,)?\\s*" );
241 static QRegExp
uninitVarRegExp(
242 "(" + dataTypeFmt
+ ")\\s*\\b([a-z][a-zA-Z_0-9]*);" );
243 static QRegExp
eqVarRegExp(
244 dataTypeFmt
+ "\\s*\\b([a-z][a-zA-Z_0-9]*)\\s*=(\\s*)(.*)" );
245 static QRegExp
ctorVarRegExp(
246 "(" + dataTypeFmt
+ ")\\s*\\b([a-z][a-zA-Z_0-9]*)\\((.*)\\);" );
247 static QRegExp
qdebugRegExp(
248 "q(?:Debug|Warning|Fatal)\\(\\s*(\"(?:\\\\.|[^\"])*\")\\s*"
249 "(?:,\\s*(\\S(?:[^,]*\\S)?))?\\s*\\);" );
250 static QRegExp
coutRegExp( "c(?:out|err)\\b(.*);" );
251 static QRegExp
lshiftRegExp( "\\s*<<\\s*" );
252 static QRegExp
endlRegExp( "^endl$" );
254 if ( code
.isEmpty() || code
== "{" || code
== "}" )
259 if ( funcPrototypeRegExp
.exactMatch(code
) ) {
260 QString returnType
= funcPrototypeRegExp
.cap( 1 );
261 QString className
= funcPrototypeRegExp
.cap( 2 );
262 QString funcName
= funcPrototypeRegExp
.cap( 3 );
263 QString params
= funcPrototypeRegExp
.cap( 4 ).trimmed();
264 bool toBeContinued
= funcPrototypeRegExp
.cap( 5 ).isEmpty();
266 Q_UNUSED(toBeContinued
);
268 className
.replace( "::", "." );
270 result
= "function " + className
+ funcName
+ "(";
272 if ( !params
.isEmpty() && params
!= "void" ) {
274 int i
= funcPrototypeRegExp
.pos( 4 );
275 while ( (i
= paramRegExp
.indexIn(code
, i
,
276 QRegExp::CaretAtOffset
)) != -1 ) {
277 QString dataType
= paramRegExp
.cap( 1 );
278 QString paramName
= paramRegExp
.cap( 2 );
279 QString comma
= paramRegExp
.cap( 3 );
281 result
+= paramName
+ " : " +
282 convertedDataType( qsTree
, dataType
);
283 if ( comma
.isEmpty() )
286 i
+= paramRegExp
.matchedLength();
292 returnType
= convertedDataType( qsTree
, returnType
);
293 if ( !returnType
.isEmpty() )
294 result
+= " : " + returnType
;
295 } else if ( uninitVarRegExp
.exactMatch(code
) ) {
296 QString dataType
= uninitVarRegExp
.cap( 1 );
297 QString varName
= uninitVarRegExp
.cap( 2 );
299 result
= "var " + varName
;
300 dataType
= convertedDataType( qsTree
, dataType
);
301 if ( !dataType
.isEmpty() )
302 result
+= " : " + dataType
;
304 } else if ( eqVarRegExp
.exactMatch(code
) ) {
305 QString varName
= eqVarRegExp
.cap( 1 );
306 QString value
= eqVarRegExp
.cap( 3 );
308 value
= convertExpr( qsTree
, value
, classesWithNoQ
);
309 result
+= "var " + varName
+ " = " + value
;
310 } else if ( ctorVarRegExp
.exactMatch(code
) ) {
311 QString dataType
= ctorVarRegExp
.cap( 1 );
312 QString varName
= ctorVarRegExp
.cap( 2 );
313 QString value
= ctorVarRegExp
.cap( 3 ).trimmed();
315 result
+= "var " + varName
+ " = ";
317 dataType
= convertedDataType( qsTree
, dataType
);
318 value
= convertExpr( qsTree
, value
, classesWithNoQ
);
320 if ( dataType
.isEmpty() || dataType
== "String" ) {
321 if ( value
.contains(",") ) {
327 result
+= "new " + dataType
;
328 if ( !value
.isEmpty() )
329 result
+= "( " + value
+ " )";
332 } else if ( qdebugRegExp
.exactMatch(code
) ) {
333 QString fmt
= qdebugRegExp
.cap( 1 );
334 QString arg1
= qdebugRegExp
.cap( 2 );
336 result
+= "println ";
338 while ( i
< (int) fmt
.length() ) {
339 if ( fmt
[i
] == '%' ) {
342 while ( i
< (int) fmt
.length() &&
343 QString("diouxXeEfFgGaAcsCSpn%\"").indexOf(fmt
[i
]) == -1 )
345 if ( fmt
[i
] == '%' ) {
347 } else if ( fmt
[i
] != '"' ) {
348 if ( percent
== 1 ) {
349 result
.truncate( result
.length() - 1 );
354 if ( arg1
.endsWith(".latin1()") )
355 arg1
.truncate( arg1
.length() - 9 );
357 if ( i
== (int) fmt
.length() - 1 ) {
368 } else if ( coutRegExp
.exactMatch(code
) &&
369 program
.filter("var cout").isEmpty() ) {
370 QStringList args
= coutRegExp
.cap(1).split(lshiftRegExp
);
371 args
.replaceInStrings( endlRegExp
, "\"\\n\"" );
372 if ( args
.last() == "\"\\n\"" ) {
373 args
.erase( args
.end() - 1 );
374 if ( args
.isEmpty() )
376 result
+= "println ";
380 result
+= args
.join( " + " ) + ";";
382 result
= convertExpr( qsTree
, code
, classesWithNoQ
);
387 QString
CppToQsConverter::convertComment( Tree
* /* qsTree */,
388 const QString
& comment
,
389 const QSet
<QString
>& classesWithNoQ
)
392 QString result
= comment
;
394 result
.replace( "TRUE", "true" );
395 result
.replace( "FALSE", "false" );
396 result
.replace( addressOperatorRegExp
, "\\1\\2" );
397 result
.replace( gulbrandsenRegExp
, "." );
400 while ( (i
= result
.indexOf(qClassRegExp
, i
)) != -1 ) {
401 if ( classesWithNoQ
.contains(qClassRegExp
.cap(1)) )
402 result
.remove( i
, 1 );
408 QString
CppToQsConverter::convertExpr( Tree
*qsTree
, const QString
& expr
,
409 const QSet
<QString
>& classesWithNoQ
)
412 return convertComment( qsTree
, expr
, classesWithNoQ
);