diff options
author | David Boddie <david.boddie@nokia.com> | 2011-01-18 19:29:44 (GMT) |
---|---|---|
committer | David Boddie <david.boddie@nokia.com> | 2011-01-18 19:29:44 (GMT) |
commit | f9d18bcf4d966c74c364dd569d5fddd262a2862c (patch) | |
tree | 717242bc970ead14324e6230a93988e121c3f193 /tools/qdoc3 | |
parent | f25ede3df41ddcd947b313b6c5fc597172f73c04 (diff) | |
download | Qt-f9d18bcf4d966c74c364dd569d5fddd262a2862c.zip Qt-f9d18bcf4d966c74c364dd569d5fddd262a2862c.tar.gz Qt-f9d18bcf4d966c74c364dd569d5fddd262a2862c.tar.bz2 |
Replaced the C++ code marker with the one from Qt Quarterly.
More changes still need to be made to restore features from the
old marker, including markup for links to classes and functions.
Diffstat (limited to 'tools/qdoc3')
-rw-r--r-- | tools/qdoc3/cppcodemarker.cpp | 483 |
1 files changed, 235 insertions, 248 deletions
diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 8ea1c7f..2b7db62 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -51,29 +51,6 @@ QT_BEGIN_NAMESPACE -static int insertTagAround(QString &result, int pos, int len, const QString &tagName, - const QString &attributes = QString()) -{ - QString s; - //s.reserve(result.size() + tagName.size() * 2 + attributes.size() + 20); - s += result.midRef(0, pos); - s += QLatin1Char('<'); - s += tagName; - if (!attributes.isEmpty()) { - s += QLatin1Char(' '); - s += attributes; - } - s += QLatin1Char('>'); - s += result.midRef(pos, len); - s += QLatin1String("</"); - s += tagName; - s += QLatin1Char('>'); - s += result.midRef(pos + len); - int diff = s.length() - result.length(); - result = s; - return diff; -} - /*! The constructor does nothing. */ @@ -159,7 +136,7 @@ QString CppCodeMarker::markedUpCode(const QString &code, const Node *relative, const Location &location) { - return addMarkUp(protect(code), relative, location); + return addMarkUp(code, relative, location); } QString CppCodeMarker::markedUpSynopsis(const Node *node, @@ -437,11 +414,11 @@ QString CppCodeMarker::markedUpIncludes(const QStringList& includes) QStringList::ConstIterator inc = includes.begin(); while (inc != includes.end()) { - code += "#include <<@headerfile>" + *inc + "</@headerfile>>\n"; + code += "<@preprocessor>#include <<@headerfile>" + *inc + "</@headerfile>></@preprocessor>\n"; ++inc; } Location location; - return addMarkUp(code, 0, location); + return code; } QString CppCodeMarker::functionBeginRegExp(const QString& funcName) @@ -867,240 +844,250 @@ const Node *CppCodeMarker::resolveTarget(const QString& target, return 0; } -QString CppCodeMarker::addMarkUp(const QString& protectedCode, +static const char * const typeTable[] = { + "bool", "char", "double", "float", "int", "long", "short", + "signed", "unsigned", "uint", "ulong", "ushort", "uchar", "void", + "qlonglong", "qulonglong", + "qint", "qint8", "qint16", "qint32", "qint64", + "quint", "quint8", "quint16", "quint32", "quint64", + "qreal", "cond", 0 +}; + +static const char * const keywordTable[] = { + "and", "and_eq", "asm", "auto", "bitand", "bitor", "break", + "case", "catch", "class", "compl", "const", "const_cast", + "continue", "default", "delete", "do", "dynamic_cast", "else", + "enum", "explicit", "export", "extern", "false", "for", "friend", + "goto", "if", "include", "inline", "monitor", "mutable", "namespace", + "new", "not", "not_eq", "operator", "or", "or_eq", "private", "protected", + "public", "register", "reinterpret_cast", "return", "sizeof", + "static", "static_cast", "struct", "switch", "template", "this", + "throw", "true", "try", "typedef", "typeid", "typename", "union", + "using", "virtual", "volatile", "wchar_t", "while", "xor", + "xor_eq", "synchronized", + // Qt specific + "signals", "slots", "emit", 0 +}; + +static QString untabified(const QString &in) +{ + QString res; + int col = 0; + int i = 0; + + for (; i < (int) in.length(); i++) { + if (in[i] == QChar('\t')) { + res += QString(" " + (col & 0x7)); + col = (col + 8) & ~0x7; + } else { + res += in[i]; + if (in[i] == QChar('\n')) + col = 0; + } + } + + return res; +} + +/* + @char + @class + @comment + @function + @keyword + @number + @op + @preprocessor + @string + @type +*/ + +QString CppCodeMarker::addMarkUp(const QString &in, const Node * /* relative */, const Location & /* location */) { - static QRegExp globalInclude("#include +<([^<>&]+)>"); - static QRegExp yHasTypeX("(?:^|\n *)([a-zA-Z_][a-zA-Z_0-9]*)" - "(?:<[^;{}]+>)?(?: *(?:\\*|&) *| +)" - "([a-zA-Z_][a-zA-Z_0-9]*)? *[,;()=]"); - static QRegExp xNewY("([a-zA-Z_][a-zA-Z_0-9]*) *= *new +([a-zA-Z_0-9]+)"); - static QRegExp xDotY("\\b([a-zA-Z_][a-zA-Z_0-9]*) *(?:\\.|->|,[ \n]*S(?:IGNAL|LOT)\\() *" - "([a-zA-Z_][a-zA-Z_0-9]*)(?= *\\()"); - static QRegExp xIsStaticZOfY("[\n:;{(=] *(([a-zA-Z_0-9]+)::([a-zA-Z_0-9]+))(?= *\\()"); - static QRegExp classX("[:,][ \n]*(?:p(?:ublic|r(?:otected|ivate))[ \n]+)?" - "([a-zA-Z_][a-zA-Z_0-9]*)"); - static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\("); - static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)"); - multiLineComment.setMinimal(true); - static QRegExp singleLineComment("[^:]//(?!!)[^!\\n]*"); - static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define" - "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)"); - static QRegExp literals(""(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*"" - "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'"); - - QString result = protectedCode; - int pos; - - if (!hurryUp()) { - /* - Mark global includes. For example: - - #include <<@headerfile>QString</@headerfile> - */ - pos = 0; - while ((pos = result.indexOf(globalInclude, pos)) != -1) - pos += globalInclude.matchedLength() - + insertTagAround(result, - globalInclude.pos(1), - globalInclude.cap(1).length(), - "@headerfile"); - - /* - Look for variable definitions and similar constructs, mark - the data type, and remember the type of the variable. - */ - QMap<QString, QSet<QString> > typesForVariable; - pos = 0; - while ((pos = yHasTypeX.indexIn(result, pos)) != -1) { - QString x = yHasTypeX.cap(1); - QString y = yHasTypeX.cap(2); - - if (!y.isEmpty()) - typesForVariable[y].insert(x); - - /* - Without the minus one at the end, 'void member(Class - var)' would give 'member' as a variable of type 'void', - but would ignore 'Class var'. (### Is that true?) - */ - pos += yHasTypeX.matchedLength() - + insertTagAround(result, - yHasTypeX.pos(1), - x.length(), - "@type") - 1; - } +#define readChar() \ + ch = (i < (int)code.length()) ? code[i++].cell() : EOF - /* - Do syntax highlighting of preprocessor directives. - */ - pos = 0; - while ((pos = preprocessor.indexIn(result, pos)) != -1) - pos += preprocessor.matchedLength() - + insertTagAround(result, - preprocessor.pos(1), - preprocessor.cap(1).length(), - "@preprocessor"); - - /* - Deal with string and character literals. - */ - pos = 0; - while ((pos = literals.indexIn(result, pos)) != -1) - pos += literals.matchedLength() - + insertTagAround(result, - pos, - literals.matchedLength(), - result.at(pos) == - QLatin1Char(' ') ? "@string" : "@char"); - - /* - Look for 'var = new Class'. - */ - pos = 0; - while ((pos = xNewY.indexIn(result, pos)) != -1) { - QString x = xNewY.cap(1); - QString y = xNewY.cap(2); - typesForVariable[x].insert(y); - - pos += xNewY.matchedLength() + insertTagAround(result, - xNewY.pos(2), - y.length(), - "@type"); - } + QString code = in; - /* - Insert some stuff that cannot harm. - */ - typesForVariable["qApp"].insert("QApplication"); - - /* - Add link to ': Class'. - */ - pos = 0; - while ((pos = classX.indexIn(result, pos)) != -1) - pos += classX.matchedLength() - + insertTagAround(result, - classX.pos(1), - classX.cap(1).length(), - "@type") - 1; - - /* - Find use of any of - - var.method() - var->method() - var, SIGNAL(method()) - var, SLOT(method()). - */ - pos = 0; - while ((pos = xDotY.indexIn(result, pos)) != -1) { - QString x = xDotY.cap(1); - QString y = xDotY.cap(2); - - QSet<QString> types = typesForVariable.value(x); - pos += xDotY.matchedLength() - + insertTagAround(result, - xDotY.pos(2), - xDotY.cap(2).length(), - "@func", - (types.count() == 1) ? "target=\"" - + protect(*types.begin() + "::" + y) - + "()\"" : QString()); - } + QMap<QString, int> types; + QMap<QString, int> keywords; + int j = 0; + while (typeTable[j] != 0) { + types.insert(QString(typeTable[j]), 0); + j++; + } + j = 0; + while (keywordTable[j] != 0) { + keywords.insert(QString(keywordTable[j]), 0); + j++; + } - /* - Add link to 'Class::method()'. - */ - pos = 0; - while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) { - QString x = xIsStaticZOfY.cap(1); - QString z = xIsStaticZOfY.cap(3); - - pos += insertTagAround(result, - xIsStaticZOfY.pos(3), - z.length(), - "@func", - "target=\"" + protect(x) + "()\""); - pos += insertTagAround(result, - xIsStaticZOfY.pos(2), - xIsStaticZOfY.cap(2).length(), - "@type"); - pos += xIsStaticZOfY.matchedLength() - 1; - } + QString out(""); + int braceDepth = 0; + int parenDepth = 0; + int i = 0; + char ch; + QRegExp classRegExp("Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)"); + QRegExp functionRegExp("q([A-Z][a-z]+)+"); + + readChar(); + + while (ch != EOF) { + int second = i; + QString tag; + + if (isalpha(ch) || ch == '_') { + QString ident; + do { + ident += ch; + readChar(); + } while (isalnum(ch) || ch == '_'); + + if (classRegExp.exactMatch(ident)) { + tag = QLatin1String("class"); + } else if (functionRegExp.exactMatch(ident)) { + tag = QLatin1String("function"); + } else if (types.contains(ident)) { + tag = QLatin1String("type"); + } else if (keywords.contains(ident)) { + tag = QLatin1String("keyword"); + } else if (braceDepth == 0 && parenDepth == 0) { + if (QString(code.unicode() + i - 1, code.length() - (i - 1)) + .indexOf(QRegExp(QLatin1String("^\\s*\\("))) == 0) + tag = QLatin1String("function"); + } + } else if (isdigit(ch)) { + do { + readChar(); + } while (isalnum(ch) || ch == '.'); + tag = QLatin1String("number"); + } else { + switch (ch) { + case '+': + case '-': + case '!': + case '%': + case '^': + case '&': + case '*': + case ',': + case '.': + case '<': + case '=': + case '>': + case '?': + case '[': + case ']': + case '|': + case '~': + readChar(); + tag = QLatin1String("op"); + break; + case '"': + readChar(); + + while (ch != EOF && ch != '"') { + if (ch == '\\') + readChar(); + readChar(); + } + readChar(); + tag = QLatin1String("string"); + break; + case '#': + readChar(); + while (ch != EOF && ch != '\n') { + if (ch == '\\') + readChar(); + readChar(); + } + tag = QLatin1String("preprocessor"); + break; + case '\'': + readChar(); + + while (ch != EOF && ch != '\'') { + if (ch == '\\') + readChar(); + readChar(); + } + readChar(); + tag = QLatin1String("char"); + break; + case '(': + readChar(); + parenDepth++; + break; + case ')': + readChar(); + parenDepth--; + break; + case ':': + readChar(); + if (ch == ':') { + readChar(); + tag = QLatin1String("op"); + } + break; + case '/': + readChar(); + if (ch == '/') { + do { + readChar(); + } while (ch != EOF && ch != '\n'); + tag = QLatin1String("comment"); + } else if (ch == '*') { + bool metAster = false; + bool metAsterSlash = false; + + readChar(); + + while (!metAsterSlash) { + if (ch == EOF) + break; + + if (ch == '*') + metAster = true; + else if (metAster && ch == '/') + metAsterSlash = true; + else + metAster = false; + readChar(); + } + tag = QLatin1String("comment"); + } else { + tag = QLatin1String("op"); + } + break; + case '{': + readChar(); + braceDepth++; + break; + case '}': + readChar(); + braceDepth--; + break; + default: + readChar(); + } + } - /* - Add link to 'globalFunction()'. - */ - pos = 0; - while ((pos = globalX.indexIn(result, pos)) != -1) { - QString x = globalX.cap(1); - if (x != "QT_FORWARD_DECLARE_CLASS") { - pos += globalX.matchedLength() - + insertTagAround(result, - globalX.pos(1), - x.length(), - "@func", - "target=\"" + protect(x) + "()\"") - 1; - } - else - pos += globalX.matchedLength(); - } - } + if (!tag.isEmpty()) + out += QLatin1String("<@") + tag + QLatin1String(">"); - /* - Do syntax highlighting of comments. Also alter the code in a - minor way, so that we can include comments in documentation - comments. - */ - pos = 0; - while (pos != -1) { - int mlpos; - int slpos; - int len; - slpos = singleLineComment.indexIn(result, pos); - mlpos = multiLineComment.indexIn(result, pos); - - if (slpos == -1 && mlpos == -1) - break; - - if (slpos == -1) { - pos = mlpos; - len = multiLineComment.matchedLength(); - } - else if (mlpos == -1) { - pos = slpos + 1; - len = singleLineComment.matchedLength() - 1; - } - else { - if (slpos < mlpos) { - pos = slpos + 1; - len = singleLineComment.matchedLength() - 1; - } - else { - pos = mlpos; - len = multiLineComment.matchedLength(); - } - } + if (tag.isEmpty() && i == code.length()) + out += protect(code.mid(second - 1, i - second + 1)); + else + out += protect(code.mid(second - 1, i - second)); - if (result.at(pos + 1) == QLatin1Char(' ')) { - result.remove(pos + len - 2, 1); - result.remove(pos + 1, 1); - len -= 2; + if (!tag.isEmpty()) + out += QLatin1String("</@") + tag + QLatin1String(">"); - forever { - int endcodePos = result.indexOf("\\ endcode", pos); - if (endcodePos == -1 || endcodePos >= pos + len) - break; - result.remove(endcodePos + 1, 1); - len -= 1; - } - } - pos += len + insertTagAround(result, pos, len, "@comment"); } - return result; + return out; } #ifdef QDOC_QML |