Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / qdoc3 / qscodeparser.cpp
blob8b3bc989e74ecfcca2423fa4e4f2f3ad579fffed
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 qscodeparser.cpp
46 #include <qfile.h>
47 #include <qregexp.h>
49 #include "config.h"
50 #include "qscodeparser.h"
51 #include "text.h"
52 #include "tokenizer.h"
53 #include "tree.h"
55 QT_BEGIN_NAMESPACE
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;
110 else {
111 config.lastLocation().warning(
112 tr("Invalid regular expression '%1'")
113 .arg(before.pattern()));
116 else {
117 config.lastLocation().warning(tr("Bad syntax in '%1'")
118 .arg(quickDotReplaces));
120 ++r;
124 void QsCodeParser::terminateParser()
126 nodeTypeMap.clear();
127 classesWithNoQuickDoc.clear();
128 replaceBefores.clear();
129 replaceAfters.clear();
130 CppCodeParser::terminateParser();
133 QString QsCodeParser::language()
135 return "Qt Script";
138 QString QsCodeParser::headerFileNameFilter()
140 return "*";
143 QString QsCodeParser::sourceFileNameFilter()
145 return "*.qs *.qsd";
148 void QsCodeParser::parseHeaderFile(const Location& location,
149 const QString& filePath,
150 Tree *tree)
152 qsTre = tree;
154 FILE *in = fopen(QFile::encodeName(filePath), "r");
155 if (in == 0) {
156 location.error(tr("Cannot open Qt Script class list '%1'")
157 .arg(filePath));
158 return;
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());
170 else {
171 fileTokenizer.location().error(tr("Unexpected token '%1' in Qt"
172 " Script class list")
173 .arg(fileTokenizer.lexeme()));
174 break;
176 tok = fileTokenizer.getToken();
178 fclose(in);
181 void QsCodeParser::parseSourceFile(const Location& location,
182 const QString& filePath,
183 Tree *tree)
185 qsTre = tree;
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);
195 ++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"
213 " class '%2'")
214 .arg(COMMAND_QUICKCLASS)
215 .arg(cwnqd.key()));
216 (*cwnqd)->setDoc(Doc(), true);
219 ++c;
222 // ### check which enum types are used
225 FunctionNode *QsCodeParser::findFunctionNode(const QString& synopsis,
226 Tree *tree)
228 QStringList parentPath;
229 FunctionNode *clone;
230 FunctionNode *func = 0;
232 if (makeFunctionNode(synopsis, &parentPath, &clone)) {
233 func = tree->findFunctionNode(parentPath, clone);
234 delete clone;
236 return func;
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,
249 const QString& arg)
251 if (command == COMMAND_QUICKFN) {
252 QStringList parentPath;
253 FunctionNode *quickFunc = 0;
254 FunctionNode *clone;
256 if (makeFunctionNode(arg, &parentPath, &clone)) {
257 FunctionNode *kernelFunc = findKernelFunction(parentPath,
258 clone->name());
259 if (kernelFunc != 0)
260 kernelFunc->setAccess(Node::Private);
262 quickFunc = qsTre->findFunctionNode(parentPath, clone);
263 if (quickFunc == 0 && kernelFunc != 0) {
264 quickFunc = new FunctionNode(kernelFunc->parent(),
265 kernelFunc->name());
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));
275 else {
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);
282 delete clone;
284 else {
285 doc.location().warning(tr("Cannot find '%1' specified with '\\%2'")
286 .arg(arg).arg(command));
288 return 0;
290 else if (nodeTypeMap.contains(command)) {
291 QStringList subArgs = arg.split(" ");
292 QString dataType;
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'")
299 .arg(command));
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));
308 else {
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'")
314 .arg(COMMAND_BRIEF)
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')")
323 .arg(command));
325 else {
326 quickProperty->setDataType(dataType);
329 else if (dataType != quickProperty->dataType()) {
330 doc.location().warning(tr("Ignored contradictory data type"
331 " in '\\%1'")
332 .arg(command));
336 return 0;
338 else {
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,
351 const QString& arg,
352 Node *node)
354 if (command == COMMAND_PROTECTED) {
355 doc.location().warning(tr("Cannot use '\\%1' in %2")
356 .arg(COMMAND_PROTECTED).arg(language()));
358 else {
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,
369 const QString& name)
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,
378 QString& source,
379 const Doc& doc)
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()));
394 else {
395 source = paras.first() + "\n\n";
399 void QsCodeParser::extractTarget(const QString& target,
400 QString& source,
401 const Doc& doc)
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);
409 int pos = 0;
410 while ((pos = source.indexOf(targetRegExp, pos)) != -1) {
411 if (targetRegExp.cap(2) == target) {
412 source = targetRegExp.cap(1) + "\n\n";
413 return;
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_]+)");
427 int pos = 0;
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);
432 if (index != -1) {
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()));
459 else {
460 doc.location().warning(
461 tr("Invalid regular expression '%1'")
462 .arg(before.pattern()));
465 else {
466 doc.location().warning(tr("Bad syntax in '\\%1'")
467 .arg(COMMAND_REPLACE));
469 ++a;
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);
482 if (codePos == -1) {
483 doc.location().warning(
484 tr("Cannot find any '\\%1' snippet corresponding to '\\%2'")
485 .arg(COMMAND_CODE).arg(COMMAND_QUICKCODE));
487 else {
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")) {
511 bare = bare.mid(1);
513 else {
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);
525 if (qtClass == 0) {
526 qtClass = wrapperClass;
527 wrapperClass = 0;
530 else if ((wrapperClass = tryClass("Quick" + bare + "Ptr")) != 0) {
531 QRegExp ptrToQtType("(Q[A-Za-z0-9_]+)\\s*\\*");
532 FunctionNode *ctor =
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);
539 else {
540 wrapperClass = tryClass("Q" + bare + "Ptr");
541 if (wrapperClass == 0)
542 wrapperClass = tryClass("Quick" + bare + "Interface");
543 qtClass = tryClass(qtClassName);
546 if (qtClass == 0) {
547 if (wrapperClass == 0) {
548 quickClass->location().warning(tr("Cannot find Qt class '%1'")
549 .arg(qtClassName));
551 else {
552 quickClass->location().warning(tr("Cannot find Qt class '%1'"
553 " wrapped by '%2'")
554 .arg(qtClassName)
555 .arg(wrapperClass->name()));
557 return;
560 QList<RelatedClass>::ConstIterator r = qtClass->baseClasses().begin();
561 while (r != qtClass->baseClasses().end()) {
562 ClassNode *quickBaseClass = cpp2qs.findClassNode(qsTre,
563 (*r).node->name());
564 if (quickBaseClass)
565 quickClass->addBaseClass((*r).access, quickBaseClass);
566 ++r;
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;
575 NodeList children;
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) {
589 if (pass == 0) {
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);
615 ++c;
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());
626 #if 0 // ### not yet
627 quickEnum->setAccess(Node::Protected);
628 #endif
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));
635 ++it;
637 setQtDoc(quickEnum, enume->doc());
640 void QsCodeParser::quickifyFunction(ClassNode *quickClass, ClassNode *qtClass,
641 FunctionNode *func, bool onBlackList)
643 if (func->metaness() == FunctionNode::Dtor)
644 return;
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());
655 if (onBlackList) {
656 quickFunc->setAccess(Node::Protected);
658 else {
659 if (kernelFunc != 0 && func->numOverloads() == 1 &&
660 (func->parameters().count() == 0 ||
661 func->parameters().last().defaultValue().isEmpty())) {
662 kernelFunc->setAccess(Node::Private);
664 else {
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(),
680 (*q).rightType());
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);
688 ++q;
691 if (func->doc().isEmpty()) {
692 if (func->parent() != (InnerNode *) qtClass) {
693 func = qtClass->findFunctionNode(func);
694 if (func != 0)
695 setQtDoc(quickFunc, func->doc());
698 else {
699 setQtDoc(quickFunc, func->doc());
703 void QsCodeParser::quickifyProperty(ClassNode *quickClass,
704 ClassNode * /* qtClass */,
705 PropertyNode *property)
707 PropertyNode *quickProperty = new PropertyNode(quickClass,
708 property->name());
709 quickProperty->setLocation(property->location());
710 quickProperty->setDataType(cpp2qs.convertedDataType(qsTre,
711 property->dataType()));
712 #if 0
713 quickProperty->setGetter(property->getter());
714 quickProperty->setSetter(property->setter());
715 quickProperty->setResetter(property->resetter());
716 #endif
717 quickProperty->setStored(property->isStored());
718 quickProperty->setDesignable(property->isDesignable());
720 setQtDoc(quickProperty, property->doc());
723 QString QsCodeParser::quickifiedDoc(const QString& source)
725 QString result;
726 int i = 0;
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") {
732 i += 2;
734 else {
735 int end = i + 1;
736 while (isWord(source[end]))
737 ++end;
738 if (!classesWithNoQ.contains(
739 source.mid(i + 1, end - (i + 1))))
740 result += "Q";
741 i++;
744 else if (source[i] == 'T' && source.mid(i, 4) == "TRUE" &&
745 rightWordBoundary(source, i + 4)) {
746 result += "\\c{true}";
747 i += 4;
749 else if (source[i] == 'F' && source.mid(i, 5) == "FALSE" &&
750 rightWordBoundary(source, i + 5)) {
751 result += "\\c{false}";
752 i += 5;
754 else if (source[i] == 'c' && source.mid(i, 6) == "const ") {
755 i += 6;
757 else {
758 result += source[i++];
761 else if ((source[i] == ':' && source[i + 1] == ':') ||
762 (source[i] == '-' && source[i + 1] == '>')) {
763 result += '.';
764 i += 2;
766 else if (source[i] == '\\') {
767 // ### make independent of the command name
768 if (source.mid(i, 5) == "\\code") {
769 do {
770 result += source[i++];
771 } while (source[i - 1] != '\n');
773 int begin = i;
774 int end = source.indexOf("\\endcode", i);
775 if (end != -1) {
776 QString code = source.mid(begin, end - begin);
777 result += cpp2qs.convertedCode(qsTre, code,
778 classesWithNoQ);
779 i = end;
782 else {
783 result += source[i++];
786 else {
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);
795 ++b;
796 ++a;
798 return result;
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,
813 const Doc& doc,
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);
827 if (pos != -1) {
828 QString quickifiedSource = quickNode->doc().source();
829 if (!qtParams.isEmpty() && qtParams != quickParams)
830 renameParameters(quickifiedSource, doc, qtParams,
831 quickParams);
832 applyReplacementList(quickifiedSource, doc);
834 do {
835 QString extract = quickifiedSource;
836 QString arg = quickifyCommand.cap(1).simplified();
837 if (!arg.isEmpty()) {
838 if (arg.startsWith("/") && arg.endsWith("/") &&
839 arg.length() > 2) {
840 QString pattern = arg.mid(1, arg.length() - 2);
841 extractRegExp(QRegExp(pattern), extract, doc);
843 else {
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(),
859 doc.location(),
860 source,
861 (CppCodeParser::topicCommands() + topicCommands() +
862 CppCodeParser::otherMetaCommands()) << COMMAND_REPLACE);
863 quickNode->setDoc(quickDoc, true);
864 processOtherMetaCommands(quickDoc, quickNode);
866 else {
867 quickNode->setDoc(doc, true);
868 processOtherMetaCommands(doc, quickNode);
872 bool QsCodeParser::makeFunctionNode(const QString& synopsis,
873 QStringList *parentPathPtr,
874 FunctionNode **funcPtr)
876 QRegExp funcRegExp(
877 "\\s*([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)\\s*\\((" +
878 balancedParens +
879 ")\\)(?:\\s*:\\s*([A-Za-z0-9_]+))?\\s*");
880 QRegExp paramRegExp(
881 "\\s*(\\[)?\\s*(?:([A-Za-z0-9_]+)\\s*:\\s*)?"
882 "([A-Za-z0-9_]+|\\.\\.\\.)\\s*(\\[)?[\\s\\]]*");
884 if (!funcRegExp.exactMatch(synopsis))
885 return false;
887 ClassNode *classe = (ClassNode*)
888 qsTre->findNode(QStringList(funcRegExp.cap(1)),Node::Class);
889 if (classe == 0)
890 return false;
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())
901 optional = true;
902 clone->addParameter(Parameter(paramRegExp.cap(3),
904 paramRegExp.cap(2),
905 optional ? "undefined" : ""));
906 if (!paramRegExp.cap(4).isEmpty())
907 optional = true;
909 else {
910 delete clone;
911 return false;
913 ++p;
915 QString returnType = funcRegExp.cap(4);
916 if (!returnType.isEmpty())
917 clone->setReturnType(returnType);
918 if (parentPathPtr != 0)
919 *parentPathPtr = QStringList() << classe->name();
920 if (funcPtr != 0) {
921 *funcPtr = clone;
923 else {
924 delete clone;
926 return true;
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]);
944 QT_END_NAMESPACE