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 ****************************************************************************/
50 #include "qscodeparser.h"
52 #include "tokenizer.h"
57 #define CONFIG_QUICK "quick"
58 #define CONFIG_REPLACES "replaces"
60 #define COMMAND_BRIEF Doc::alias( "brief")
61 #define COMMAND_CODE Doc::alias( "code")
62 #define COMMAND_ENDCODE Doc::alias( "endcode")
63 #define COMMAND_ENDQUICKCODE Doc::alias( "endquickcode")
64 #define COMMAND_FILE Doc::alias( "file")
65 #define COMMAND_GROUP Doc::alias( "group")
66 #define COMMAND_MODULE Doc::alias( "module")
67 #define COMMAND_PAGE Doc::alias( "page")
68 #define COMMAND_QUICKCLASS Doc::alias( "quickclass")
69 #define COMMAND_QUICKCODE Doc::alias( "quickcode")
70 #define COMMAND_QUICKENUM Doc::alias( "quickenum")
71 #define COMMAND_QUICKFN Doc::alias( "quickfn")
72 #define COMMAND_QUICKIFY Doc::alias( "quickify")
73 #define COMMAND_QUICKPROPERTY Doc::alias( "quickproperty")
74 #define COMMAND_PROTECTED Doc::alias( "protected")
75 #define COMMAND_REPLACE Doc::alias( "replace")
77 static QString balancedParens
= "(?:[^()]+|\\([^()]*\\))*";
79 QsCodeParser::QsCodeParser(Tree
*cppTree
)
80 : cppTre(cppTree
), qsTre(0), replaceRegExp("/(.+)/([^/]*)/")
84 QsCodeParser::~QsCodeParser()
88 void QsCodeParser::initializeParser(const Config
& config
)
90 CppCodeParser::initializeParser(config
);
92 nodeTypeMap
.insert(COMMAND_QUICKCLASS
, Node::Class
);
93 nodeTypeMap
.insert(COMMAND_QUICKENUM
, Node::Enum
);
94 nodeTypeMap
.insert(COMMAND_QUICKPROPERTY
, Node::Property
);
95 nodeTypeMap
.insert(COMMAND_QUICKFN
, Node::Function
);
97 QString quickDotReplaces
= CONFIG_QUICK
+ Config::dot
+ CONFIG_REPLACES
;
98 QStringList replaces
= config
.getStringList(quickDotReplaces
);
99 QStringList::ConstIterator r
= replaces
.begin();
100 while (r
!= replaces
.end()) {
101 if (replaceRegExp
.exactMatch(*r
)) {
102 QRegExp
before(replaceRegExp
.cap(1));
103 before
.setMinimal(true);
104 QString after
= replaceRegExp
.cap(2);
106 if (before
.isValid()) {
107 replaceBefores
<< before
;
108 replaceAfters
<< after
;
111 config
.lastLocation().warning(
112 tr("Invalid regular expression '%1'")
113 .arg(before
.pattern()));
117 config
.lastLocation().warning(tr("Bad syntax in '%1'")
118 .arg(quickDotReplaces
));
124 void QsCodeParser::terminateParser()
127 classesWithNoQuickDoc
.clear();
128 replaceBefores
.clear();
129 replaceAfters
.clear();
130 CppCodeParser::terminateParser();
133 QString
QsCodeParser::language()
138 QString
QsCodeParser::headerFileNameFilter()
143 QString
QsCodeParser::sourceFileNameFilter()
148 void QsCodeParser::parseHeaderFile(const Location
& location
,
149 const QString
& filePath
,
154 FILE *in
= fopen(QFile::encodeName(filePath
), "r");
156 location
.error(tr("Cannot open Qt Script class list '%1'")
161 Location
fileLocation(filePath
);
162 Tokenizer
fileTokenizer(fileLocation
, in
);
163 int tok
= fileTokenizer
.getToken();
164 while (tok
!= Tok_Eoi
) {
165 if (tok
== Tok_Ident
) {
166 ClassNode
*quickClass
= new ClassNode(qsTre
->root(),
167 fileTokenizer
.lexeme());
168 quickClass
->setLocation(fileTokenizer
.location());
171 fileTokenizer
.location().error(tr("Unexpected token '%1' in Qt"
172 " Script class list")
173 .arg(fileTokenizer
.lexeme()));
176 tok
= fileTokenizer
.getToken();
181 void QsCodeParser::parseSourceFile(const Location
& location
,
182 const QString
& filePath
,
186 CppCodeParser::parseSourceFile(location
, filePath
, tree
);
189 void QsCodeParser::doneParsingHeaderFiles(Tree
*tree
)
191 NodeList::ConstIterator c
= tree
->root()->childNodes().begin();
192 while (c
!= tree
->root()->childNodes().end()) {
193 if ((*c
)->type() == Node::Class
)
194 quickifyClass((ClassNode
*) *c
);
197 cppTre
->root()->deleteChildren(); // save memory
198 tree
->resolveInheritance();
199 tree
->resolveProperties();
202 void QsCodeParser::doneParsingSourceFiles(Tree
*tree
)
204 tree
->root()->normalizeOverloads();
206 NodeList::ConstIterator c
= tree
->root()->childNodes().begin();
207 while (c
!= tree
->root()->childNodes().end()) {
208 if ((*c
)->type() == Node::Class
) {
209 QMap
<QString
, Node
*>::ConstIterator cwnqd
=
210 classesWithNoQuickDoc
.find((*c
)->name());
211 if (cwnqd
!= classesWithNoQuickDoc
.end()) {
212 (*cwnqd
)->location().warning(tr("No '\\%1' documentation for"
214 .arg(COMMAND_QUICKCLASS
)
216 (*cwnqd
)->setDoc(Doc(), true);
222 // ### check which enum types are used
225 FunctionNode
*QsCodeParser::findFunctionNode(const QString
& synopsis
,
228 QStringList parentPath
;
230 FunctionNode
*func
= 0;
232 if (makeFunctionNode(synopsis
, &parentPath
, &clone
)) {
233 func
= tree
->findFunctionNode(parentPath
, clone
);
239 QSet
<QString
> QsCodeParser::topicCommands()
241 return QSet
<QString
>() << COMMAND_FILE
<< COMMAND_GROUP
<< COMMAND_MODULE
242 << COMMAND_PAGE
<< COMMAND_QUICKCLASS
243 << COMMAND_QUICKENUM
<< COMMAND_QUICKFN
244 << COMMAND_QUICKPROPERTY
;
247 Node
*QsCodeParser::processTopicCommand(const Doc
& doc
,
248 const QString
& command
,
251 if (command
== COMMAND_QUICKFN
) {
252 QStringList parentPath
;
253 FunctionNode
*quickFunc
= 0;
256 if (makeFunctionNode(arg
, &parentPath
, &clone
)) {
257 FunctionNode
*kernelFunc
= findKernelFunction(parentPath
,
260 kernelFunc
->setAccess(Node::Private
);
262 quickFunc
= qsTre
->findFunctionNode(parentPath
, clone
);
263 if (quickFunc
== 0 && kernelFunc
!= 0) {
264 quickFunc
= new FunctionNode(kernelFunc
->parent(),
266 quickFunc
->setLocation(kernelFunc
->location());
267 quickFunc
->setReturnType(clone
->returnType());
268 quickFunc
->setParameters(clone
->parameters());
271 if (quickFunc
== 0) {
272 doc
.location().warning(tr("Cannot find '%1' specified with '\\%2'")
273 .arg(arg
).arg(command
));
276 quickFunc
->setAccess(Node::Public
);
277 QStringList qtParams
= quickFunc
->parameterNames();
278 quickFunc
->borrowParameterNames(clone
);
279 QStringList quickParams
= quickFunc
->parameterNames();
280 setQuickDoc(quickFunc
, doc
, qtParams
, quickParams
);
285 doc
.location().warning(tr("Cannot find '%1' specified with '\\%2'")
286 .arg(arg
).arg(command
));
290 else if (nodeTypeMap
.contains(command
)) {
291 QStringList subArgs
= arg
.split(" ");
294 if (subArgs
.count() == 3 && subArgs
[1] == ":") {
295 dataType
= subArgs
[2];
297 else if (subArgs
.count() != 1) {
298 doc
.location().warning(tr("Invalid syntax in '\\%1'")
302 QStringList path
= subArgs
[0].split(".");
303 Node
*quickNode
= qsTre
->findNode(path
, nodeTypeMap
[command
]);
304 if (quickNode
== 0) {
305 doc
.location().warning(tr("Cannot find '%1' specified with '\\%2'")
306 .arg(arg
).arg(command
));
309 setQuickDoc(quickNode
, doc
);
310 if (quickNode
->type() == Node::Class
) {
311 classesWithNoQuickDoc
.remove(quickNode
->name());
312 if (doc
.briefText().isEmpty())
313 doc
.location().warning(tr("Missing '\\%1' for class '%2'")
315 .arg(quickNode
->name()));
317 else if (quickNode
->type() == Node::Property
) {
318 PropertyNode
*quickProperty
= (PropertyNode
*) quickNode
;
319 if (quickProperty
->dataType() == "Object") {
320 if (dataType
.isEmpty()) {
321 doc
.location().warning(tr("Missing data type in '\\%1'"
322 " (assuming 'Object')")
326 quickProperty
->setDataType(dataType
);
329 else if (dataType
!= quickProperty
->dataType()) {
330 doc
.location().warning(tr("Ignored contradictory data type"
339 return CppCodeParser::processTopicCommand(doc
, command
, arg
);
343 QSet
<QString
> QsCodeParser::otherMetaCommands()
345 return commonMetaCommands() << COMMAND_ENDQUICKCODE
<< COMMAND_QUICKCODE
346 << COMMAND_QUICKIFY
<< COMMAND_REPLACE
;
349 void QsCodeParser::processOtherMetaCommand(const Doc
& doc
,
350 const QString
& command
,
354 if (command
== COMMAND_PROTECTED
) {
355 doc
.location().warning(tr("Cannot use '\\%1' in %2")
356 .arg(COMMAND_PROTECTED
).arg(language()));
359 CppCodeParser::processOtherMetaCommand(doc
,command
,arg
,node
);
363 ClassNode
*QsCodeParser::tryClass(const QString
& className
)
365 return (ClassNode
*) cppTre
->findNode(QStringList(className
),Node::Class
);
368 FunctionNode
*QsCodeParser::findKernelFunction(const QStringList
& parentPath
,
371 FunctionNode
clone(0, name
);
372 clone
.setReturnType("Object");
373 clone
.addParameter(Parameter("..."));
374 return qsTre
->findFunctionNode(parentPath
, &clone
);
377 void QsCodeParser::extractRegExp(const QRegExp
& regExp
,
381 QRegExp
blankLineRegExp(
382 "[ \t]*(?:\n(?:[ \t]*\n)+[ \t]*|[ \n\t]*\\\\code|"
383 "\\\\endcode[ \n\t]*)");
384 QStringList paras
= source
.trimmed().split(blankLineRegExp
);
385 paras
= paras
.filter(regExp
);
386 if (paras
.count() == 0) {
387 doc
.location().warning(tr("Cannot find regular expression '%1'")
388 .arg(regExp
.pattern()));
390 else if (paras
.count() > 1) {
391 doc
.location().warning(tr("Regular rexpression '%1' matches multiple"
392 "times").arg(regExp
.pattern()));
395 source
= paras
.first() + "\n\n";
399 void QsCodeParser::extractTarget(const QString
& target
,
403 QRegExp
targetRegExp(
404 "(\\\\target\\s+(\\S+)[^\n]*\n"
405 "(?:(?!\\s*\\\\code)[^\n]+\n|\\s*\\\\code.*\\\\endcode\\s*\n)*)"
406 "(?:\\s*\n|[^\n]*$)");
407 targetRegExp
.setMinimal(true);
410 while ((pos
= source
.indexOf(targetRegExp
, pos
)) != -1) {
411 if (targetRegExp
.cap(2) == target
) {
412 source
= targetRegExp
.cap(1) + "\n\n";
415 pos
+= targetRegExp
.matchedLength();
417 doc
.location().warning(tr("Cannot find target '%1'").arg(target
));
420 void QsCodeParser::renameParameters(QString
& source
,
421 const Doc
& /* doc */,
422 const QStringList
& qtParams
,
423 const QStringList
& quickParams
)
425 QRegExp
paramRegExp("(\\\\a\\s*\\{?\\s*)([A-Za-z0-9_]+)");
428 while ((pos
= paramRegExp
.indexIn(source
, pos
)) != -1) {
429 pos
+= paramRegExp
.cap(1).length();
430 QString before
= paramRegExp
.cap(2);
431 int index
= qtParams
.indexOf(before
);
433 QString after
= quickParams
[index
];
434 source
.replace(pos
, before
.size(), after
);
439 void QsCodeParser::applyReplacementList(QString
& source
, const Doc
& doc
)
441 QStringList args
= doc
.metaCommandArgs(COMMAND_REPLACE
);
442 QStringList::ConstIterator a
= args
.begin();
443 while (a
!= args
.end()) {
444 if (replaceRegExp
.exactMatch(*a
)) {
445 QRegExp
before(replaceRegExp
.cap(1));
446 before
.setMinimal(true);
447 QString after
= replaceRegExp
.cap(2);
449 if (before
.isValid()) {
450 int oldLen
= source
.size();
451 source
.replace(before
, after
);
453 // this condition is sufficient but not necessary
454 if (oldLen
== source
.size() && !source
.contains(after
))
455 doc
.location().warning(
456 tr("Regular expression '%1' did not match anything")
457 .arg(before
.pattern()));
460 doc
.location().warning(
461 tr("Invalid regular expression '%1'")
462 .arg(before
.pattern()));
466 doc
.location().warning(tr("Bad syntax in '\\%1'")
467 .arg(COMMAND_REPLACE
));
472 QRegExp
codeRegExp("\\\\" + COMMAND_CODE
+ "(.*)\\\\" + COMMAND_ENDCODE
);
473 codeRegExp
.setMinimal(true);
475 QRegExp
quickcodeRegExp(
476 "\\\\" + COMMAND_QUICKCODE
+ "(.*)\\\\" + COMMAND_ENDQUICKCODE
);
477 quickcodeRegExp
.setMinimal(true);
479 int quickcodePos
= doc
.source().indexOf(quickcodeRegExp
);
480 if (quickcodePos
!= -1) {
481 int codePos
= source
.indexOf(codeRegExp
);
483 doc
.location().warning(
484 tr("Cannot find any '\\%1' snippet corresponding to '\\%2'")
485 .arg(COMMAND_CODE
).arg(COMMAND_QUICKCODE
));
488 source
.replace(codeRegExp
.pos(1), codeRegExp
.cap(1).length(),
489 quickcodeRegExp
.cap(1));
490 codePos
= codeRegExp
.pos(1) + quickcodeRegExp
.cap(1).length();
492 if (doc
.source().indexOf(quickcodeRegExp
, quickcodePos
+ 1) != -1) {
493 doc
.location().warning(
494 tr("Cannot use '\\%1' twice in a row")
495 .arg(COMMAND_QUICKCODE
));
497 else if (source
.indexOf(codeRegExp
, codePos
+ 1) != -1) {
498 doc
.location().warning(tr("Ambiguous '\\%1'")
499 .arg(COMMAND_QUICKCODE
));
505 void QsCodeParser::quickifyClass(ClassNode
*quickClass
)
507 QString qtClassName
= quickClass
->name();
508 QString bare
= quickClass
->name();
509 if (bare
!= "Qt" && bare
!= "Object") {
510 if (bare
.startsWith("Q")) {
514 qtClassName
.prepend("Q");
515 classesWithNoQ
.insert(bare
);
519 ClassNode
*qtClass
= 0;
520 ClassNode
*wrapperClass
= 0;
522 if ((wrapperClass
= tryClass("Quick" + bare
)) != 0 ||
523 (wrapperClass
= tryClass("QS" + bare
+ "Class")) != 0) {
524 qtClass
= tryClass(qtClassName
);
526 qtClass
= wrapperClass
;
530 else if ((wrapperClass
= tryClass("Quick" + bare
+ "Ptr")) != 0) {
531 QRegExp
ptrToQtType("(Q[A-Za-z0-9_]+)\\s*\\*");
533 wrapperClass
->findFunctionNode(wrapperClass
->name());
534 if (ctor
!= 0 && !ctor
->parameters().isEmpty() &&
535 ptrToQtType
.exactMatch(ctor
->parameters().first().leftType()))
536 qtClassName
= ptrToQtType
.cap(1);
537 qtClass
= tryClass(qtClassName
);
540 wrapperClass
= tryClass("Q" + bare
+ "Ptr");
541 if (wrapperClass
== 0)
542 wrapperClass
= tryClass("Quick" + bare
+ "Interface");
543 qtClass
= tryClass(qtClassName
);
547 if (wrapperClass
== 0) {
548 quickClass
->location().warning(tr("Cannot find Qt class '%1'")
552 quickClass
->location().warning(tr("Cannot find Qt class '%1'"
555 .arg(wrapperClass
->name()));
560 QList
<RelatedClass
>::ConstIterator r
= qtClass
->baseClasses().begin();
561 while (r
!= qtClass
->baseClasses().end()) {
562 ClassNode
*quickBaseClass
= cpp2qs
.findClassNode(qsTre
,
565 quickClass
->addBaseClass((*r
).access
, quickBaseClass
);
568 if (quickClass
->baseClasses().isEmpty() && quickClass
->name() != "Object")
569 quickClass
->addBaseClass(Node::Public
,
570 cpp2qs
.findClassNode(qsTre
,"Object"));
572 QSet
<QString
> funcBlackList
;
573 QSet
<QString
> propertyBlackList
;
576 if (wrapperClass
!= 0) {
577 children
= wrapperClass
->childNodes();
579 funcBlackList
.insert(wrapperClass
->name());
580 funcBlackList
.insert("~" + wrapperClass
->name());
582 children
+= qtClass
->childNodes();
584 for (int pass
= 0; pass
< 2; pass
++) {
585 NodeList::ConstIterator c
= children
.begin();
586 while (c
!= children
.end()) {
587 if ((*c
)->access() != Node::Private
&&
588 (*c
)->status() == Node::Commendable
) {
590 if ((*c
)->type() == Node::Enum
) {
591 EnumNode
*enume
= (EnumNode
*) *c
;
592 quickifyEnum(quickClass
, enume
);
594 else if ((*c
)->type() == Node::Property
) {
595 if (!propertyBlackList
.contains((*c
)->name())) {
596 PropertyNode
*property
= (PropertyNode
*) *c
;
597 quickifyProperty(quickClass
, qtClass
, property
);
598 if (!property
->getters().isEmpty())
599 funcBlackList
.insert(property
->getters().first()->name());
600 if (!property
->setters().isEmpty())
601 funcBlackList
.insert(property
->setters().first()->name());
602 if (!property
->resetters().isEmpty())
603 funcBlackList
.insert(property
->resetters().first()->name());
604 propertyBlackList
.insert(property
->name());
608 else if ((*c
)->type() == Node::Function
) {
609 FunctionNode
*func
= (FunctionNode
*) *c
;
610 quickifyFunction(quickClass
, qtClass
, func
,
611 funcBlackList
.contains((*c
)->name()) &&
612 func
->parameters().count() < 2);
618 setQtDoc(quickClass
, qtClass
->doc());
619 classesWithNoQuickDoc
.insert(quickClass
->name(), quickClass
);
622 void QsCodeParser::quickifyEnum(ClassNode
*quickClass
, EnumNode
*enume
)
624 EnumNode
*quickEnum
= new EnumNode(quickClass
, enume
->name());
625 quickEnum
->setLocation(enume
->location());
627 quickEnum
->setAccess(Node::Protected
);
630 QList
<EnumItem
>::ConstIterator it
= enume
->items().begin();
631 while (it
!= enume
->items().end()) {
632 QString name
= (*it
).name();
633 QString value
= (*it
).value();
634 quickEnum
->addItem(EnumItem(name
, value
));
637 setQtDoc(quickEnum
, enume
->doc());
640 void QsCodeParser::quickifyFunction(ClassNode
*quickClass
, ClassNode
*qtClass
,
641 FunctionNode
*func
, bool onBlackList
)
643 if (func
->metaness() == FunctionNode::Dtor
)
646 FunctionNode
*kernelFunc
= findKernelFunction(
647 QStringList() << quickClass
->name(), func
->name());
649 QString quickName
= func
->name();
650 if (func
->metaness() == FunctionNode::Ctor
)
651 quickName
= quickClass
->name();
652 FunctionNode
*quickFunc
= new FunctionNode(quickClass
, quickName
);
653 quickFunc
->setLocation(func
->location());
656 quickFunc
->setAccess(Node::Protected
);
659 if (kernelFunc
!= 0 && func
->numOverloads() == 1 &&
660 (func
->parameters().count() == 0 ||
661 func
->parameters().last().defaultValue().isEmpty())) {
662 kernelFunc
->setAccess(Node::Private
);
665 if (func
->metaness() == FunctionNode::Plain
)
666 quickFunc
->setAccess(Node::Protected
);
670 quickFunc
->setReturnType(cpp2qs
.convertedDataType(qsTre
,
671 func
->returnType()));
672 if (func
->metaness() != FunctionNode::Slot
)
673 quickFunc
->setMetaness(func
->metaness());
674 quickFunc
->setVirtualness(FunctionNode::ImpureVirtual
);
675 quickFunc
->setOverload(func
->isOverload());
677 QList
<Parameter
>::ConstIterator q
= func
->parameters().begin();
678 while (q
!= func
->parameters().end()) {
679 QString dataType
= cpp2qs
.convertedDataType(qsTre
, (*q
).leftType(),
681 if (dataType
.isEmpty()) {
682 dataType
= "UNKNOWN";
683 quickFunc
->setAccess(Node::Private
);
685 Parameter
param(dataType
, "", (*q
).name(),
686 (*q
).defaultValue().isEmpty() ? "" : "undefined");
687 quickFunc
->addParameter(param
);
691 if (func
->doc().isEmpty()) {
692 if (func
->parent() != (InnerNode
*) qtClass
) {
693 func
= qtClass
->findFunctionNode(func
);
695 setQtDoc(quickFunc
, func
->doc());
699 setQtDoc(quickFunc
, func
->doc());
703 void QsCodeParser::quickifyProperty(ClassNode
*quickClass
,
704 ClassNode
* /* qtClass */,
705 PropertyNode
*property
)
707 PropertyNode
*quickProperty
= new PropertyNode(quickClass
,
709 quickProperty
->setLocation(property
->location());
710 quickProperty
->setDataType(cpp2qs
.convertedDataType(qsTre
,
711 property
->dataType()));
713 quickProperty
->setGetter(property
->getter());
714 quickProperty
->setSetter(property
->setter());
715 quickProperty
->setResetter(property
->resetter());
717 quickProperty
->setStored(property
->isStored());
718 quickProperty
->setDesignable(property
->isDesignable());
720 setQtDoc(quickProperty
, property
->doc());
723 QString
QsCodeParser::quickifiedDoc(const QString
& source
)
728 while (i
< (int) source
.length()) {
729 if (leftWordBoundary(source
, i
)) {
730 if (source
[i
] == 'Q') {
731 if (source
[i
+ 1] == 'C' && source
.mid(i
, 8) == "QCString") {
736 while (isWord(source
[end
]))
738 if (!classesWithNoQ
.contains(
739 source
.mid(i
+ 1, end
- (i
+ 1))))
744 else if (source
[i
] == 'T' && source
.mid(i
, 4) == "TRUE" &&
745 rightWordBoundary(source
, i
+ 4)) {
746 result
+= "\\c{true}";
749 else if (source
[i
] == 'F' && source
.mid(i
, 5) == "FALSE" &&
750 rightWordBoundary(source
, i
+ 5)) {
751 result
+= "\\c{false}";
754 else if (source
[i
] == 'c' && source
.mid(i
, 6) == "const ") {
758 result
+= source
[i
++];
761 else if ((source
[i
] == ':' && source
[i
+ 1] == ':') ||
762 (source
[i
] == '-' && source
[i
+ 1] == '>')) {
766 else if (source
[i
] == '\\') {
767 // ### make independent of the command name
768 if (source
.mid(i
, 5) == "\\code") {
770 result
+= source
[i
++];
771 } while (source
[i
- 1] != '\n');
774 int end
= source
.indexOf("\\endcode", i
);
776 QString code
= source
.mid(begin
, end
- begin
);
777 result
+= cpp2qs
.convertedCode(qsTre
, code
,
783 result
+= source
[i
++];
787 result
+= source
[i
++];
791 QList
<QRegExp
>::ConstIterator b
= replaceBefores
.begin();
792 QStringList::ConstIterator a
= replaceAfters
.begin();
793 while (a
!= replaceAfters
.end()) {
794 result
.replace(*b
, *a
);
801 void QsCodeParser::setQtDoc(Node
*quickNode
, const Doc
& doc
)
803 if (!doc
.isEmpty()) {
804 Doc
quickDoc(doc
.location(), doc
.location(),
805 quickifiedDoc(doc
.source()),
806 CppCodeParser::topicCommands() +
807 CppCodeParser::otherMetaCommands());
808 quickNode
->setDoc(quickDoc
, true);
812 void QsCodeParser::setQuickDoc(Node
*quickNode
,
814 const QStringList
& qtParams
,
815 const QStringList
& quickParams
)
817 QRegExp
quickifyCommand("\\\\" + COMMAND_QUICKIFY
+ "([^\n]*)(?:\n|$)");
819 if (quickNode
->type() == Node::Function
) {
820 FunctionNode
*quickFunc
= (FunctionNode
*) quickNode
;
821 quickFunc
->setOverload(false);
824 if (doc
.metaCommandsUsed().contains(COMMAND_QUICKIFY
)) {
825 QString source
= doc
.source();
826 int pos
= source
.indexOf(quickifyCommand
);
828 QString quickifiedSource
= quickNode
->doc().source();
829 if (!qtParams
.isEmpty() && qtParams
!= quickParams
)
830 renameParameters(quickifiedSource
, doc
, qtParams
,
832 applyReplacementList(quickifiedSource
, doc
);
835 QString extract
= quickifiedSource
;
836 QString arg
= quickifyCommand
.cap(1).simplified();
837 if (!arg
.isEmpty()) {
838 if (arg
.startsWith("/") && arg
.endsWith("/") &&
840 QString pattern
= arg
.mid(1, arg
.length() - 2);
841 extractRegExp(QRegExp(pattern
), extract
, doc
);
844 extractTarget(arg
, extract
, doc
);
847 source
.replace(pos
, quickifyCommand
.matchedLength(), extract
);
848 pos
+= extract
.length();
849 } while ((pos
= source
.indexOf(quickifyCommand
, pos
)) != -1);
851 QRegExp
quickcodeRegExp(
852 "\\\\" + COMMAND_QUICKCODE
+ "(.*)\\\\" +
853 COMMAND_ENDQUICKCODE
);
854 quickcodeRegExp
.setMinimal(true);
855 source
.replace(quickcodeRegExp
, "");
858 Doc
quickDoc(doc
.location(),
861 (CppCodeParser::topicCommands() + topicCommands() +
862 CppCodeParser::otherMetaCommands()) << COMMAND_REPLACE
);
863 quickNode
->setDoc(quickDoc
, true);
864 processOtherMetaCommands(quickDoc
, quickNode
);
867 quickNode
->setDoc(doc
, true);
868 processOtherMetaCommands(doc
, quickNode
);
872 bool QsCodeParser::makeFunctionNode(const QString
& synopsis
,
873 QStringList
*parentPathPtr
,
874 FunctionNode
**funcPtr
)
877 "\\s*([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)\\s*\\((" +
879 ")\\)(?:\\s*:\\s*([A-Za-z0-9_]+))?\\s*");
881 "\\s*(\\[)?\\s*(?:([A-Za-z0-9_]+)\\s*:\\s*)?"
882 "([A-Za-z0-9_]+|\\.\\.\\.)\\s*(\\[)?[\\s\\]]*");
884 if (!funcRegExp
.exactMatch(synopsis
))
887 ClassNode
*classe
= (ClassNode
*)
888 qsTre
->findNode(QStringList(funcRegExp
.cap(1)),Node::Class
);
892 FunctionNode
*clone
= new FunctionNode(0, funcRegExp
.cap(2));
893 bool optional
= false;
895 QString paramStr
= funcRegExp
.cap(3);
896 QStringList params
= paramStr
.split(",");
897 QStringList::ConstIterator p
= params
.begin();
898 while (p
!= params
.end()) {
899 if (paramRegExp
.exactMatch(*p
)) {
900 if (!paramRegExp
.cap(1).isEmpty())
902 clone
->addParameter(Parameter(paramRegExp
.cap(3),
905 optional
? "undefined" : ""));
906 if (!paramRegExp
.cap(4).isEmpty())
915 QString returnType
= funcRegExp
.cap(4);
916 if (!returnType
.isEmpty())
917 clone
->setReturnType(returnType
);
918 if (parentPathPtr
!= 0)
919 *parentPathPtr
= QStringList() << classe
->name();
929 bool QsCodeParser::isWord(QChar ch
)
931 return ch
.isLetterOrNumber() || ch
== QChar('_');
934 bool QsCodeParser::leftWordBoundary(const QString
& str
, int pos
)
936 return !isWord(str
[pos
- 1]) && isWord(str
[pos
]);
939 bool QsCodeParser::rightWordBoundary(const QString
& str
, int pos
)
941 return isWord(str
[pos
- 1]) && !isWord(str
[pos
]);