Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / qdoc3 / cpptoqsconverter.cpp
blob1a44c160f873593fc1169bdbb90dac0c0c7af184
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the tools applications of the Qt Toolkit.
8 **
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
14 ** this package.
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.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
43 cpptoqsconverter.cpp
46 #include "config.h"
47 #include "cpptoqsconverter.h"
49 QT_BEGIN_NAMESPACE
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 );
70 if ( classe == 0 )
71 classe = (ClassNode *) qsTree->findNode( QStringList(qtName.mid(1)), Node::Class );
72 return classe;
75 QString CppToQsConverter::convertedDataType( Tree *qsTree,
76 const QString& leftType,
77 const QString& /* rightType */ )
79 QString s = leftType;
81 if ( s.startsWith("const ") )
82 s = s.mid( 6 );
83 while ( s.endsWith("*") || s.endsWith("&") || s.endsWith(" ") )
84 s.truncate( s.length() - 1 );
86 switch ( s[0].unicode() ) {
87 case 'Q':
88 if ( s == "QCString" ) {
89 return "String";
90 } else {
91 Node *node = findClassNode( qsTree, s );
92 if ( node == 0 ) {
93 return "";
94 } else {
95 return node->name();
98 break;
99 case 'b':
100 if ( s == "bool" )
101 return "Boolean";
102 break;
103 case 'c':
104 if ( s == "char" ) {
105 if ( leftType == "const char *" ) {
106 return "String";
107 } else {
108 return "Number";
111 break;
112 case 'd':
113 if ( s == "double" )
114 return "Number";
115 break;
116 case 'f':
117 if ( s == "float" )
118 return "Number";
119 case 'i':
120 if ( s == "int" )
121 return "Number";
122 break;
123 case 'l':
124 if ( s == "long" || s == "long int" || s == "long long" ||
125 s == "long long int" || s == "long double" )
126 return "Number";
127 break;
128 case 's':
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" )
132 return "Number";
133 break;
134 case 'u':
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" )
139 return "Number";
140 break;
141 case 'v':
142 if ( s == "void" )
143 return "";
145 return s;
148 QString CppToQsConverter::convertedCode( Tree *qsTree, const QString& code,
149 const QSet<QString>& classesWithNoQ )
151 QString result;
152 QStringList program;
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();
160 QString comment;
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;
182 ++ol;
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() )
191 result += "\n";
193 if ( (*p).trimmed().isEmpty() ) {
194 if ( !(*c).isEmpty() )
195 result += *p;
196 } else {
197 result += *p;
198 if ( !(*c).isEmpty() ) {
199 int i = columnForIndex( *p, (*p).length() );
200 while ( i++ < programWidth )
201 result += " ";
204 result += *c;
205 ++p;
206 ++c;
208 return result;
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 );
221 if ( size > 0 )
222 setIndentSize( size );
225 void CppToQsConverter::terminate()
229 QString CppToQsConverter::convertCodeLine( Tree *qsTree,
230 const QStringList& program,
231 const QString& code,
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 == "}" )
255 return code;
257 QString result;
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();
265 // ### unused
266 Q_UNUSED(toBeContinued);
268 className.replace( "::", "." );
270 result = "function " + className + funcName + "(";
272 if ( !params.isEmpty() && params != "void" ) {
273 result += " ";
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() )
284 break;
285 result += ", ";
286 i += paramRegExp.matchedLength();
288 result += " ";
291 result += ")";
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;
303 result += ";";
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(",") ) {
322 result += "...";
323 } else {
324 result += value;
326 } else {
327 result += "new " + dataType;
328 if ( !value.isEmpty() )
329 result += "( " + value + " )";
331 result += ";";
332 } else if ( qdebugRegExp.exactMatch(code) ) {
333 QString fmt = qdebugRegExp.cap( 1 );
334 QString arg1 = qdebugRegExp.cap( 2 );
336 result += "println ";
337 int i = 0;
338 while ( i < (int) fmt.length() ) {
339 if ( fmt[i] == '%' ) {
340 int percent = i;
341 i++;
342 while ( i < (int) fmt.length() &&
343 QString("diouxXeEfFgGaAcsCSpn%\"").indexOf(fmt[i]) == -1 )
344 i++;
345 if ( fmt[i] == '%' ) {
346 result += fmt[i++];
347 } else if ( fmt[i] != '"' ) {
348 if ( percent == 1 ) {
349 result.truncate( result.length() - 1 );
350 } else {
351 result += "\" + ";
353 i++;
354 if ( arg1.endsWith(".latin1()") )
355 arg1.truncate( arg1.length() - 9 );
356 result += arg1;
357 if ( i == (int) fmt.length() - 1 ) {
358 i++;
359 } else {
360 result += " + \"";
363 } else {
364 result += fmt[i++];
367 result += ";";
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() )
375 args << "\"\"";
376 result += "println ";
377 } else {
378 result += "print ";
380 result += args.join( " + " ) + ";";
381 } else {
382 result = convertExpr( qsTree, code, classesWithNoQ );
384 return result;
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, "." );
399 int i = 0;
400 while ( (i = result.indexOf(qClassRegExp, i)) != -1 ) {
401 if ( classesWithNoQ.contains(qClassRegExp.cap(1)) )
402 result.remove( i, 1 );
403 i++;
405 return result;
408 QString CppToQsConverter::convertExpr( Tree *qsTree, const QString& expr,
409 const QSet<QString>& classesWithNoQ )
411 // suboptimal
412 return convertComment( qsTree, expr, classesWithNoQ );
415 QT_END_NAMESPACE