diff options
author | Cary Clark <caryclark@skia.org> | 2017-09-19 17:39:32 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-09-19 22:04:19 +0000 |
commit | 9174bda24aef222beaff1d9d80ea80a063852c74 (patch) | |
tree | 7143dfc0f50303df1adf8f6fa9186f39bf2a1c18 | |
parent | fe69f9a50ac1a6a61c9dda9c28c97599131656ee (diff) |
work on generation of rect, bitmap, matrix markup
TBR=caryclark@google.com
Bug: skia:6898
Change-Id: I501d87341afa2f8d548b4d02415375032a46e96e
Reviewed-on: https://skia-review.googlesource.com/47420
Reviewed-by: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
-rw-r--r-- | tools/bookmaker/bookmaker.cpp | 3 | ||||
-rw-r--r-- | tools/bookmaker/bookmaker.h | 161 | ||||
-rw-r--r-- | tools/bookmaker/includeParser.cpp | 604 |
3 files changed, 533 insertions, 235 deletions
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp index ffe04810d5..ac1a4a9939 100644 --- a/tools/bookmaker/bookmaker.cpp +++ b/tools/bookmaker/bookmaker.cpp @@ -2258,6 +2258,7 @@ int main(int argc, char** const argv) { return -1; } if (!FLAGS_tokens.isEmpty()) { + includeParser.fDebugOut = FLAGS_stdout; if (includeParser.dumpTokens(FLAGS_tokens[0])) { bmhParser.fWroteOut = true; } @@ -2290,6 +2291,7 @@ int main(int argc, char** const argv) { } if (!done && !FLAGS_ref.isEmpty() && FLAGS_examples.isEmpty()) { MdOut mdOut(bmhParser); + mdOut.fDebugOut = FLAGS_stdout; if (mdOut.buildReferences(FLAGS_bmh[0], FLAGS_ref[0])) { bmhParser.fWroteOut = true; } @@ -2306,6 +2308,7 @@ int main(int argc, char** const argv) { if (!bmhParser.checkExamples()) { return -1; } + bmhParser.fDebugOut = FLAGS_stdout; if (!bmhParser.dumpExamples(FLAGS_examples[0])) { return -1; } diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h index 1d95f13453..4e93f88faf 100644 --- a/tools/bookmaker/bookmaker.h +++ b/tools/bookmaker/bookmaker.h @@ -880,6 +880,12 @@ public: return result; } + template <typename T> T reportError(const char* errorStr) const { + TextParser tp(this); + tp.reportError(errorStr); + return T(); + } + virtual RootDefinition* rootParent() { SkASSERT(0); return nullptr; } void setParentIndex() { @@ -1034,7 +1040,7 @@ public: fLinefeeds = 0; fSpaces = 0; fColumn = 0; - fPendingSpace = false; + fPendingSpace = 0; } bool parseFile(const char* file, const char* suffix); @@ -1056,7 +1062,7 @@ public: fOut = nullptr; fMaxLF = 2; fPendingLF = 0; - fPendingSpace = false; + fPendingSpace = 0; nl(); } @@ -1081,6 +1087,7 @@ public: --size; } if (size <= 0) { + fLastChar = '\0'; return false; } SkASSERT(size < 16000); @@ -1088,7 +1095,7 @@ public: fMaxLF = 1; } if (this->leadingPunctuation(data, (size_t) size)) { - fPendingSpace = false; + fPendingSpace = 0; } writePending(); if (fDebugOut) { @@ -1100,6 +1107,7 @@ public: } fprintf(fOut, "%.*s", size, data); int added = 0; + fLastChar = data[size - 1]; while (size > 0 && '\n' != data[--size]) { ++added; } @@ -1126,36 +1134,39 @@ public: // write a pending space, so that two consecutive calls // don't double write, and trailing spaces on lines aren't written - void writeSpace() { + void writeSpace(int count = 1) { SkASSERT(!fPendingLF); SkASSERT(!fLinefeeds); SkASSERT(fColumn > 0); SkASSERT(!fSpaces); - fPendingSpace = true; + fPendingSpace = count; } void writeString(const char* str) { - SkASSERT(strlen(str) > 0); + const size_t len = strlen(str); + SkASSERT(len > 0); SkASSERT(' ' < str[0]); - SkASSERT(' ' < str[strlen(str) - 1]); + fLastChar = str[len - 1]; + SkASSERT(' ' < fLastChar); + SkASSERT(!strchr(str, '\n')); if (this->leadingPunctuation(str, strlen(str))) { - fPendingSpace = false; + fPendingSpace = 0; } writePending(); if (fDebugOut) { - if (!strncmp("SK_SUPPORT", str, 10)) { - SkDebugf(""); - } SkDebugf("%s", str); } - SkASSERT(!strchr(str, '\n')); fprintf(fOut, "%s", str); - fColumn += strlen(str); + fColumn += len; fSpaces = 0; fLinefeeds = 0; fMaxLF = 2; } + void writeString(const string& str) { + this->writeString(str.c_str()); + } + void writePending() { fPendingLF = SkTMin(fPendingLF, fMaxLF); bool wroteLF = false; @@ -1178,14 +1189,14 @@ public: fColumn = fIndent; fSpaces = fIndent; } - if (fPendingSpace) { + for (int index = 0; index < fPendingSpace; ++index) { if (fDebugOut) { SkDebugf(" "); } fprintf(fOut, " "); ++fColumn; - fPendingSpace = false; } + fPendingSpace = 0; } unordered_map<string, sk_sp<SkData>> fRawData; @@ -1193,13 +1204,14 @@ public: Definition* fParent; FILE* fOut; int fLinefeeds; // number of linefeeds last written, zeroed on non-space - int fMaxLF; // number of linefeeds allowed - int fPendingLF; // number of linefeeds to write (can be suppressed) - int fSpaces; // number of spaces (indent) last written, zeroed on non-space - int fColumn; // current column; number of chars past last linefeed - int fIndent; // desired indention - bool fPendingSpace; // a space should preceed the next string or block - bool fDebugOut; // set true to write to std out + int fMaxLF; // number of linefeeds allowed + int fPendingLF; // number of linefeeds to write (can be suppressed) + int fSpaces; // number of spaces (indent) last written, zeroed on non-space + int fColumn; // current column; number of chars past last linefeed + int fIndent; // desired indention + int fPendingSpace; // one or two spaces should preceed the next string or block + char fLastChar; // last written + bool fDebugOut; // set true to write to std out private: typedef TextParser INHERITED; }; @@ -1515,8 +1527,12 @@ public: bool crossCheck(BmhParser& ); IClassDefinition* defineClass(const Definition& includeDef, const string& className); void dumpClassTokens(IClassDefinition& classDef); - void dumpComment(Definition* token); + void dumpComment(const Definition& ); + void dumpEnum(const Definition& ); + void dumpMethod(const Definition& ); + void dumpMember(const Definition& ); bool dumpTokens(const string& directory); + bool dumpTokens(const string& directory, const string& skClassName); bool findComments(const Definition& includeDef, Definition* markupDef); Definition* findIncludeObject(const Definition& includeDef, MarkType markType, @@ -1547,8 +1563,6 @@ public: static KeyWord FindKey(const char* start, const char* end); bool internalName(const Definition& ) const; - void keywordEnd(); - void keywordStart(const char* keyword); bool parseChar(); bool parseComment(const string& filename, const char* start, const char* end, int lineCount, Definition* markupDef); @@ -1636,6 +1650,103 @@ public: void validate() const; + void writeDefinition(const Definition& def) { + if (def.length() > 1) { + this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart); + this->lf(1); + } + } + + void writeDefinition(const Definition& def, const string& name, int spaces) { + this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart); + this->writeSpace(spaces); + this->writeString(name); + this->lf(1); + } + + void writeEndTag() { + this->lf(1); + this->writeString("##"); + this->lf(1); + } + + void writeEndTag(const char* tagType) { + this->lf(1); + this->writeString(string("#") + tagType + " ##"); + this->lf(1); + } + + void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) { + this->lf(1); + this->writeString(string("#") + tagType + " " + tagID); + this->writeSpace(spaces); + this->writeString("##"); + this->lf(1); + } + + void writeEndTag(const char* tagType, const string& tagID, int spaces = 1) { + this->writeEndTag(tagType, tagID.c_str(), spaces); + } + + void writeTableHeader(const char* col1, size_t pad, const char* col2) { + this->lf(1); + this->writeString("#Table"); + this->lf(1); + this->writeString("#Legend"); + this->lf(1); + string legend = "# "; + legend += col1; + if (pad > strlen(col1)) { + legend += string(pad - strlen(col1), ' '); + } + legend += " # "; + legend += col2; + legend += " ##"; + this->writeString(legend); + this->lf(1); + this->writeString("#Legend ##"); + this->lf(1); + } + + void writeTableRow(size_t pad, const string& col1) { + this->lf(1); + string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##"; + this->writeString(row); + this->lf(1); + } + + void writeTableTrailer() { + this->lf(1); + this->writeString("#Table ##"); + this->lf(1); + } + + void writeTag(const char* tagType) { + this->lf(1); + this->writeString("#"); + this->writeString(tagType); + } + + void writeTagNoLF(const char* tagType, const char* tagID) { + this->writeString("#"); + this->writeString(tagType); + this->writeSpace(); + this->writeString(tagID); + } + + void writeTagNoLF(const char* tagType, const string& tagID) { + this->writeTagNoLF(tagType, tagID.c_str()); + } + + void writeTag(const char* tagType, const char* tagID) { + this->lf(1); + this->writeTagNoLF(tagType, tagID); + } + + void writeTag(const char* tagType, const string& tagID) { + this->writeTag(tagType, tagID.c_str()); + } + protected: static void ValidateKeyWords(); diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp index 1000a037e7..ee2b95a134 100644 --- a/tools/bookmaker/includeParser.cpp +++ b/tools/bookmaker/includeParser.cpp @@ -105,9 +105,7 @@ void IncludeParser::checkForMissingParams(const vector<string>& methodParams, } } if (!found) { - this->keywordStart("Param"); - fprintf(fOut, "%s ", methodParam.c_str()); - this->keywordEnd(); + this->writeEndTag("Param", methodParam, 2); } } for (auto& foundParam : foundParams) { @@ -450,90 +448,38 @@ void IncludeParser::dumpClassTokens(IClassDefinition& classDef) { continue; } if (MarkType::kMember != token.fMarkType) { - fprintf(fOut, "%s", - "# ------------------------------------------------------------------------------\n"); - fprintf(fOut, "" "\n"); + this->writeString( + "# ------------------------------------------------------------------------------"); + this->lf(2); } switch (token.fMarkType) { case MarkType::kEnum: - fprintf(fOut, "#Enum %s" "\n", - token.fName.c_str()); - fprintf(fOut, "" "\n"); - fprintf(fOut, "#Code" "\n"); - fprintf(fOut, " enum %s {" "\n", - token.fName.c_str()); - for (auto& child : token.fChildren) { - fprintf(fOut, " %s %.*s" "\n", - child->fName.c_str(), child->length(), child->fContentStart); - } - fprintf(fOut, " };" "\n"); - fprintf(fOut, "##" "\n"); - fprintf(fOut, "" "\n"); - this->dumpComment(&token); - for (auto& child : token.fChildren) { - fprintf(fOut, "#Const %s", child->fName.c_str()); - TextParser val(child); - if (!val.eof()) { - if ('=' == val.fStart[0] || ',' == val.fStart[0]) { - val.next(); - val.skipSpace(); - const char* valEnd = val.anyOf(",\n"); - if (!valEnd) { - valEnd = val.fEnd; - } - fprintf(fOut, " %.*s", (int) (valEnd - val.fStart), val.fStart); - } else { - fprintf(fOut, " %.*s", - (int) (child->fContentEnd - child->fContentStart), - child->fContentStart); - } - } - fprintf(fOut, "" "\n"); - for (auto& token : child->fTokens) { - if (MarkType::kComment == token.fMarkType) { - this->dumpComment(&token); - } - } - fprintf(fOut, "##" "\n"); - } - fprintf(fOut, "" "\n"); + this->dumpEnum(token); break; case MarkType::kMethod: - fprintf(fOut, "#Method %.*s" "\n", - token.length(), token.fStart); - lfAlways(1); - this->dumpComment(&token); + this->dumpMethod(token); break; case MarkType::kMember: - this->keywordStart("Member"); - fprintf(fOut, "%.*s %s ", (int) (token.fContentEnd - token.fContentStart), - token.fContentStart, token.fName.c_str()); - lfAlways(1); - for (auto child : token.fChildren) { - fprintf(fOut, "%.*s", (int) (child->fContentEnd - child->fContentStart), - child->fContentStart); - lfAlways(1); - } - this->keywordEnd(); + this->dumpMember(token); continue; break; default: SkASSERT(0); } this->lf(2); - fprintf(fOut, "#Example" "\n"); - fprintf(fOut, "##" "\n"); - fprintf(fOut, "" "\n"); - fprintf(fOut, "#ToDo incomplete ##" "\n"); - fprintf(fOut, "" "\n"); - fprintf(fOut, "##" "\n"); - fprintf(fOut, "" "\n"); + this->writeTag("Example"); + this->writeEndTag(); + this->lf(2); + this->writeEndTag("ToDo", "incomplete"); + this->lf(2); + this->writeEndTag(); + this->lf(2); } } -void IncludeParser::dumpComment(Definition* token) { - fLineCount = token->fLineCount; - fChar = fLine = token->fContentStart; - fEnd = token->fContentEnd; +void IncludeParser::dumpComment(const Definition& token) { + fLineCount = token.fLineCount; + fChar = fLine = token.fContentStart; + fEnd = token.fContentEnd; bool sawParam = false; bool multiline = false; bool sawReturn = false; @@ -542,11 +488,11 @@ void IncludeParser::dumpComment(Definition* token) { vector<string> methodParams; vector<string> foundParams; Definition methodName; - TextParser methodParser(token->fFileName, token->fContentStart, token->fContentEnd, - token->fLineCount); - if (MarkType::kMethod == token->fMarkType) { - methodName.fName = string(token->fContentStart, - (int) (token->fContentEnd - token->fContentStart)); + TextParser methodParser(token.fFileName, token.fContentStart, token.fContentEnd, + token.fLineCount); + if (MarkType::kMethod == token.fMarkType) { + methodName.fName = string(token.fContentStart, + (int) (token.fContentEnd - token.fContentStart)); methodHasReturn = !methodParser.startsWith("void ") && !methodParser.strnchr('~', methodParser.fEnd); const char* paren = methodParser.strnchr('(', methodParser.fEnd); @@ -561,8 +507,14 @@ void IncludeParser::dumpComment(Definition* token) { methodParams.push_back(paramName); } while (')' != nextEnd[0]); } - for (const auto& child : token->fTokens) { + for (const auto& child : token.fTokens) { + if (Definition::Type::kMark == child.fType && MarkType::kMember == child.fMarkType) { + break; + } if (Definition::Type::kMark == child.fType && MarkType::kComment == child.fMarkType) { + if (child.fPrivate) { + break; + } if ('@' == child.fContentStart[0]) { TextParser parser(&child); do { @@ -585,9 +537,9 @@ void IncludeParser::dumpComment(Definition* token) { } if (sawParam) { if (multiline) { - this->lfAlways(1); + this->lf(1); } - this->keywordEnd(); + this->writeEndTag(); } else { if (sawComment) { this->nl(); @@ -595,10 +547,10 @@ void IncludeParser::dumpComment(Definition* token) { this->lf(2); } foundParams.emplace_back(piece); - this->keywordStart("Param"); - fprintf(fOut, "%s ", piece.c_str()); - fprintf(fOut, "%.*s", (int) (parser.fEnd - parser.fChar), parser.fChar); - this->lfAlways(1); + this->writeTag("Param", piece); + this->writeSpace(2); + this->writeBlock(parser.fEnd - parser.fChar, parser.fChar); + this->lf(1); sawParam = true; sawComment = false; } while (parmName.length()); @@ -610,43 +562,59 @@ void IncludeParser::dumpComment(Definition* token) { } if (sawParam) { if (multiline) { - this->lfAlways(1); + this->lf(1); } - this->keywordEnd(); + this->writeEndTag(); } this->checkForMissingParams(methodParams, foundParams); sawParam = false; sawComment = false; multiline = false; this->lf(2); - this->keywordStart("Return"); - fprintf(fOut, "%.*s ", (int) (parser.fEnd - parser.fChar), - parser.fChar); - this->lfAlways(1); + this->writeTag("Return"); + this->writeSpace(2); + this->writeBlock(parser.fEnd - parser.fChar, parser.fChar); + this->lf(1); sawReturn = true; parser.skipTo(parser.fEnd); } else { this->reportError("unexpected doxygen directive"); } } while (!parser.eof()); - } else { - if (sawComment) { - this->nl(); + } else if (child.length() > 1) { + const char* start = child.fContentStart; + ptrdiff_t length = child.fContentEnd - start; + SkASSERT(length >= 0); + while (length && '/' == start[0]) { + start += 1; + --length; } - this->lf(1); - fprintf(fOut, "%.*s ", child.length(), child.fContentStart); - sawComment = true; - if (sawParam || sawReturn) { - multiline = true; + while (length && '/' == start[length - 1]) { + length -= 1; + if (length && '*' == start[length - 1]) { + length -= 1; + } + } + if (length) { + this->lfAlways(sawComment || sawParam || sawReturn ? 1 : 2); + if (sawParam || sawReturn) { + this->indentToColumn(8); + } + this->writeBlock(length, start); + this->writeSpace(); + sawComment = true; + if (sawParam || sawReturn) { + multiline = true; + } } } } } if (sawParam || sawReturn) { if (multiline) { - this->lfAlways(1); + this->lf(1); } - this->keywordEnd(); + this->writeEndTag(); } if (!sawReturn) { if (!sawParam) { @@ -665,15 +633,145 @@ void IncludeParser::dumpComment(Definition* token) { this->nl(); } this->lf(2); - this->keywordStart("Return"); - this->keywordEnd(); + this->writeEndTag("Return"); } } } - // dump equivalent markup +void IncludeParser::dumpEnum(const Definition& token) { + this->writeTag("Enum", token.fName); + this->lf(2); + this->writeString("#Code"); + this->lfAlways(1); + this->indentToColumn(4); + this->writeString("enum"); + this->writeSpace(); + if ("_anonymous" != token.fName.substr(0, 10)) { + this->writeString(token.fName); + this->writeSpace(); + } + this->writeString("{"); + this->lfAlways(1); + for (auto& child : token.fChildren) { + this->indentToColumn(8); + this->writeString(child->fName); + if (child->length()) { + this->writeSpace(); + this->writeBlock(child->length(), child->fContentStart); + } + if (',' != fLastChar) { + this->writeString(","); + } + this->lfAlways(1); + } + this->indentToColumn(4); + this->writeString("};"); + this->lf(1); + this->writeString("##"); + this->lf(2); + this->dumpComment(token); + for (auto& child : token.fChildren) { + // start here; + // get comments before + // or after const values + this->writeString("#Const"); + this->writeSpace(); + this->writeString(child->fName); + TextParser val(child); + if (!val.eof()) { + if ('=' == val.fStart[0] || ',' == val.fStart[0]) { + val.next(); + val.skipSpace(); + const char* valEnd = val.anyOf(",\n"); + if (!valEnd) { + valEnd = val.fEnd; + } + this->writeSpace(); + this->writeBlock(valEnd - val.fStart, val.fStart); + } else { + this->writeSpace(); + this->writeDefinition(*child); + } + } + this->lf(1); + for (auto comment : child->fChildren) { + if (MarkType::kComment == comment->fMarkType) { + TextParser parser(comment); + parser.skipExact("*"); + parser.skipExact("*"); + while (!parser.eof() && parser.skipWhiteSpace()) { + parser.skipExact("*"); + parser.skipWhiteSpace(); + const char* start = parser.fChar; + parser.skipToEndBracket('\n'); + this->lf(1); + this->writeBlock(parser.fChar - start, start); + } + } + } + this->writeEndTag(); + } + this->lf(2); +} + +void IncludeParser::dumpMethod(const Definition& token) { + this->writeString("#Method"); + this->writeSpace(); + if ("SK_TO_STRING_NONVIRT" == token.fName) { + this->writeString("void toString(SkString* str) const;"); + this->lf(2); + this->writeEndTag("DefinedBy", "SK_TO_STRING_NONVIRT()"); + this->lf(2); + this->writeTag("Private"); + this->lf(1); + this->writeString("macro expands to: void toString(SkString* str) const;"); + this->writeEndTag(); + this->lf(2); + const char desc[] = + "Creates string representation. The representation is read by\n" + "internal debugging tools. The interface and implementation may be\n" + "suppressed by defining SK_IGNORE_TO_STRING."; + this->writeBlock(sizeof(desc) - 1, desc); + this->lf(2); + this->writeTag("Param", "str"); + this->writeSpace(2); + this->writeString("storage for string representation"); + this->writeSpace(); + this->writeString("##"); + this->lf(2); + return; + } + this->writeBlock(token.length(), token.fStart); + this->lf(1); + this->dumpComment(token); +} + +void IncludeParser::dumpMember(const Definition& token) { + this->writeTag("Member"); + this->writeSpace(); + this->writeDefinition(token, token.fName, 2); + lf(1); + for (auto child : token.fChildren) { + this->writeDefinition(*child); + } + this->writeEndTag(); + lf(2); +} + bool IncludeParser::dumpTokens(const string& dir) { - string skClassName = this->className(); + for (const auto& member : fIClassMap) { + if (string::npos != member.first.find("::")) { + continue; + } + if (!this->dumpTokens(dir, member.first)) { + return false; + } + } + return true; +} + + // dump equivalent markup +bool IncludeParser::dumpTokens(const string& dir, const string& skClassName) { string fileName = dir; if (dir.length() && '/' != dir[dir.length() - 1]) { fileName += '/'; @@ -687,19 +785,20 @@ bool IncludeParser::dumpTokens(const string& dir) { string prefixName = skClassName.substr(0, 2); string topicName = skClassName.length() > 2 && isupper(skClassName[2]) && ("Sk" == prefixName || "Gr" == prefixName) ? skClassName.substr(2) : skClassName; - fprintf(fOut, "#Topic %s", topicName.c_str()); - this->lfAlways(2); - fprintf(fOut, "#Class %s", skClassName.c_str()); - this->lfAlways(2); + this->writeTagNoLF("Topic", topicName); + this->writeTag("Alias", topicName + "_Reference"); + this->lf(2); auto& classMap = fIClassMap[skClassName]; + const char* containerType = kKeyWords[(int) classMap.fKeyWord].fName; + this->writeTag(containerType, skClassName); + this->lf(2); auto& tokens = classMap.fTokens; for (auto& token : tokens) { if (Definition::Type::kMark != token.fType || MarkType::kComment != token.fMarkType) { continue; } - fprintf(fOut, "%.*s", (int) (token.fContentEnd - token.fContentStart), - token.fContentStart); - this->lfAlways(1); + this->writeDefinition(token); + this->lf(1); } this->lf(2); string className(skClassName.substr(2)); @@ -713,96 +812,129 @@ bool IncludeParser::dumpTokens(const string& dir) { maxLen = SkTMax(maxLen, structName.length()); sortedClasses.emplace_back(structName); } - fprintf(fOut, "#Topic Overview"); - this->lfAlways(2); - fprintf(fOut, "#Subtopic %s_Structs", className.c_str()); - this->lfAlways(1); - fprintf(fOut, "#Table"); - this->lfAlways(1); - fprintf(fOut, "#Legend"); - this->lfAlways(1); - fprintf(fOut, "# %-*s # description ##", (int) maxLen, "struct"); - this->lfAlways(1); - fprintf(fOut, "#Legend ##"); - this->lfAlways(1); - fprintf(fOut, "#Table ##"); - this->lfAlways(1); - for (auto& name : sortedClasses) { - fprintf(fOut, "# %-*s # ##", (int) maxLen, name.c_str()); - this->lfAlways(1); + this->writeTag("Topic", "Overview"); + this->lf(2); + this->writeTag("Subtopic", "Subtopics"); + this->writeEndTag("ToDo", "manually add subtopics"); + this->writeTableHeader("topics", 0, "description"); + this->writeTableTrailer(); + this->writeEndTag(); + this->lf(2); + if (maxLen) { + this->writeTag("Subtopic", "Structs"); + this->writeTableHeader("description", maxLen, "struct"); + for (auto& name : sortedClasses) { + this->writeTableRow(maxLen, name); + } + this->writeTableTrailer(); + this->writeEndTag("Subtopic"); + this->lf(2); } - fprintf(fOut, "#Subtopic ##"); - this->lfAlways(2); - fprintf(fOut, "#Subtopic %s_Member_Functions", className.c_str()); - this->lfAlways(1); - fprintf(fOut, "#Table"); - this->lfAlways(1); - fprintf(fOut, "#Legend"); - this->lfAlways(1); maxLen = 0; + size_t constructorMax = 0; + size_t operatorMax = 0; vector<string> sortedNames; + vector<string> constructorNames; + vector<string> operatorNames; for (const auto& token : classMap.fTokens) { if (Definition::Type::kMark != token.fType || MarkType::kMethod != token.fMarkType) { continue; } - const string& name = token.fName; + string name = token.fName; if (name.substr(0, 7) == "android" || string::npos != name.find("nternal_")) { continue; } + if ((name.substr(0, 2) == "Sk" && 2 == name.find(className)) || '~' == name[0]) { + name = string(token.fContentStart, (int) (token.fContentEnd - token.fContentStart)); + constructorMax = SkTMax(constructorMax, name.length()); + constructorNames.emplace_back(name); + continue; + } + if (name.substr(0, 8) == "operator") { + name = string(token.fContentStart, (int) (token.fContentEnd - token.fContentStart)); + operatorMax = SkTMax(operatorMax, name.length()); + operatorNames.emplace_back(name); + continue; + } if (name[name.length() - 2] == '_' && isdigit(name[name.length() - 1])) { continue; } + if ("SK_TO_STRING_NONVIRT" == name) { + name = "toString"; + } size_t paren = name.find('('); size_t funcLen = string::npos == paren ? name.length() : paren; maxLen = SkTMax(maxLen, funcLen); sortedNames.emplace_back(name); } + if (constructorMax) { + std::sort(constructorNames.begin(), constructorNames.end()); + this->writeTag("Subtopic", "Constructors"); + this->writeTableHeader("description", constructorMax, "function"); + for (auto& name : constructorNames) { + this->writeTableRow(constructorMax, name); + } + this->writeTableTrailer(); + this->writeEndTag("Subtopic"); + this->lf(2); + } + if (operatorMax) { + std::sort(operatorNames.begin(), operatorNames.end()); + this->writeTag("Subtopic", "Operators"); + this->writeTableHeader("description", operatorMax, "function"); + for (auto& name : operatorNames) { + this->writeTableRow(operatorMax, name); + } + this->writeTableTrailer(); + this->writeEndTag("Subtopic"); + this->lf(2); + } std::sort(sortedNames.begin(), sortedNames.end()); - fprintf(fOut, "# %-*s # description ##" "\n", - (int) maxLen, "function"); - fprintf(fOut, "#Legend ##" "\n"); + this->writeTag("Subtopic", "Member_Functions"); + this->writeTableHeader("description", maxLen, "function"); for (auto& name : sortedNames) { size_t paren = name.find('('); size_t funcLen = string::npos == paren ? name.length() : paren; - fprintf(fOut, "# %-*s # ##" "\n", - (int) maxLen, name.substr(0, funcLen).c_str()); - } - fprintf(fOut, "#Table ##" "\n"); - fprintf(fOut, "#Subtopic ##" "\n"); - fprintf(fOut, "" "\n"); - fprintf(fOut, "#Topic ##" "\n"); - fprintf(fOut, "" "\n"); + this->writeTableRow(maxLen, name.substr(0, funcLen)); + } + this->writeTableTrailer(); + this->writeEndTag("Subtopic"); + this->lf(2); + this->writeEndTag("Topic"); + this->lf(2); for (auto& oneClass : fIClassMap) { if (skClassName + "::" != oneClass.first.substr(0, skClassName.length() + 2)) { continue; } string innerName = oneClass.first.substr(skClassName.length() + 2); - fprintf(fOut, "%s", + this->writeString( "# ------------------------------------------------------------------------------"); - this->lfAlways(2); - fprintf(fOut, "#Struct %s", innerName.c_str()); - this->lfAlways(2); + this->lf(2); + const char* containerType = kKeyWords[(int) oneClass.second.fKeyWord].fName; + this->writeTag(containerType, innerName); + this->lf(2); + this->writeTag("Code"); + this->writeEndTag("ToDo", "fill this in manually"); + this->writeEndTag(); + this->lf(2); for (auto& token : oneClass.second.fTokens) { if (Definition::Type::kMark != token.fType || MarkType::kComment != token.fMarkType) { continue; } - fprintf(fOut, "%.*s", (int) (token.fContentEnd - token.fContentStart), - token.fContentStart); - this->lfAlways(1); + this->writeDefinition(token); } this->lf(2); this->dumpClassTokens(oneClass.second); this->lf(2); - fprintf(fOut, "#Struct %s ##", innerName.c_str()); - this->lfAlways(2); + this->writeEndTag(containerType, innerName); + this->lf(2); } this->dumpClassTokens(classMap); - fprintf(fOut, "#Class %s ##" "\n", - skClassName.c_str()); - fprintf(fOut, "" "\n"); - fprintf(fOut, "#Topic %s ##" "\n", - topicName.c_str()); + this->writeEndTag(containerType, skClassName); + this->lf(2); + this->writeEndTag("Topic", topicName); + this->lfAlways(1); fclose(fOut); SkDebugf("wrote %s\n", fileName.c_str()); return true; @@ -859,9 +991,6 @@ bool IncludeParser::internalName(const Definition& token) const { // caller calls reportError, so just return false here bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) { SkASSERT(includeDef->fTokens.size() > 0); - if (includeDef->fTokens.size() == 1) { - return true; // forward declaration only - } // parse class header auto iter = includeDef->fTokens.begin(); if (!strncmp(iter->fStart, "SK_API", iter->fContentEnd - iter->fStart)) { @@ -870,24 +999,28 @@ bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) { } string nameStr(iter->fStart, iter->fContentEnd - iter->fStart); includeDef->fName = nameStr; + iter = std::next(iter); + if (iter == includeDef->fTokens.end()) { + return true; // forward declaration only + } do { if (iter == includeDef->fTokens.end()) { - return false; + return includeDef->reportError<bool>("unexpected end"); } if ('{' == iter->fStart[0] && Definition::Type::kPunctuation == iter->fType) { break; } } while (static_cast<void>(iter = std::next(iter)), true); if (Punctuation::kLeftBrace != iter->fPunctuation) { - return false; + return iter->reportError<bool>("expected left brace"); } IClassDefinition* markupDef = this->defineClass(*includeDef, nameStr); if (!markupDef) { - return false; + return iter->reportError<bool>("expected markup definition"); } markupDef->fStart = iter->fStart; if (!this->findComments(*includeDef, markupDef)) { - return false; + return iter->reportError<bool>("find comments failed"); } // if (1 != includeDef->fChildren.size()) { // return false; // fix me: SkCanvasClipVisitor isn't correctly parsed @@ -1018,9 +1151,9 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) { } TextParser parser(child); parser.skipToEndBracket('{'); + parser.next(); const char* dataEnd; do { - parser.next(); parser.skipWhiteSpace(); if ('}' == parser.peek()) { break; @@ -1058,33 +1191,57 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) { if ('}' == memberStart[0]) { break; } + // if there's comment on same the line as member def, output first as if it was before + parser.skipToNonAlphaNum(); string memberName(memberStart, parser.fChar); - parser.skipWhiteSpace(); + if (parser.eof() || !parser.skipWhiteSpace()) { + return this->reportError<bool>("enum member must end with comma 1"); + } const char* dataStart = parser.fChar; - SkASSERT('=' == dataStart[0] || ',' == dataStart[0] || '}' == dataStart[0] - || '/' == dataStart[0]); - dataEnd = parser.anyOf(",}"); + if ('=' == parser.peek()) { + parser.skipToEndBracket(','); + } + if (parser.eof() || ',' != parser.peek()) { + return this->reportError<bool>("enum member must end with comma 2"); + } + dataEnd = parser.fChar; + const char* start = parser.anyOf("/\n"); + SkASSERT(start); + parser.skipTo(start); + if ('/' == parser.next()) { + char slashStar = parser.next(); + if ('/' == slashStar || '*' == slashStar) { + TextParser::Save save(&parser); + char doxCheck = parser.next(); + if ((slashStar != doxCheck && '!' != doxCheck) || '<' != parser.next()) { + save.restore(); + } + } + parser.skipWhiteSpace(); + const char* commentStart = parser.fChar; + if ('/' == slashStar) { + parser.skipToEndBracket('\n'); + } else { + parser.skipToEndBracket("*/"); + } + SkASSERT(!parser.eof()); + const char* commentEnd = parser.fChar; + markupChild->fTokens.emplace_back(MarkType::kComment, commentStart, commentEnd, + parser.fLineCount, markupChild); + comment = &markupChild->fTokens.back(); + comment->fTerminator = commentEnd; + } markupChild->fTokens.emplace_back(MarkType::kMember, dataStart, dataEnd, parser.fLineCount, markupChild); Definition* member = &markupChild->fTokens.back(); member->fName = memberName; if (comment) { member->fChildren.push_back(comment); + comment->fPrivate = true; } markupChild->fChildren.push_back(member); - parser.skipToEndBracket(dataEnd[0]); - } while (',' == dataEnd[0]); - for (size_t index = 1; index < child->fChildren.size(); ++index) { - const Definition* follower = child->fChildren[index]; - if (Definition::Type::kKeyWord == follower->fType) { - markupChild->fTokens.emplace_back(MarkType::kMember, follower->fContentStart, - follower->fContentEnd, follower->fLineCount, markupChild); - Definition* member = &markupChild->fTokens.back(); - member->fName = follower->fName; - markupChild->fChildren.push_back(member); - } - } + } while (true); IClassDefinition& classDef = fIClassMap[markupDef->fName]; SkASSERT(classDef.fStart); string uniqueName = this->uniqueName(classDef.fEnums, nameStr); @@ -1125,6 +1282,7 @@ bool IncludeParser::parseMember(Definition* child, Definition* markupDef) { IClassDefinition& classDef = fIClassMap[markupDef->fName]; string uniqueName = this->uniqueName(classDef.fMethods, nameStr); markupChild->fName = uniqueName; + markupChild->fTerminator = markupChild->fContentEnd; classDef.fMembers[uniqueName] = markupChild; if (child->fParentIndex >= 2) { auto comment = child->fParent->fTokens.begin(); @@ -1162,6 +1320,9 @@ bool IncludeParser::parseMethod(Definition* child, Definition* markupDef) { std::advance(tokenIter, child->fParentIndex); tokenIter = std::prev(tokenIter); string nameStr(tokenIter->fStart, tokenIter->fContentEnd - tokenIter->fStart); + if (0 == nameStr.find("SK_ATTR_DEPRECATED")) { + SkDebugf(""); + } while (tokenIter != child->fParent->fTokens.begin()) { auto testIter = std::prev(tokenIter); switch (testIter->fType) { @@ -1231,6 +1392,17 @@ bool IncludeParser::parseMethod(Definition* child, Definition* markupDef) { while (end > start && ' ' >= end[-1]) { --end; } + if (!markupDef) { + auto parentIter = child->fParent->fTokens.begin(); + SkASSERT(child->fParentIndex > 0); + std::advance(parentIter, child->fParentIndex - 1); + Definition* methodName = &*parentIter; + TextParser name(methodName); + if (name.skipToEndBracket(':') && name.startsWith("::")) { + return true; // expect this is inline class definition outside of class + } + SkASSERT(0); // code incomplete + } markupDef->fTokens.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount, markupDef); Definition* markupChild = &markupDef->fTokens.back(); @@ -1246,16 +1418,6 @@ bool IncludeParser::parseMethod(Definition* child, Definition* markupDef) { return true; } -void IncludeParser::keywordEnd() { - fprintf(fOut, "##"); - this->lfAlways(1); -} - -void IncludeParser::keywordStart(const char* keyword) { - this->lf(1); - fprintf(fOut, "#%s ", keyword); -} - bool IncludeParser::parseObjects(Definition* parent, Definition* markupDef) { for (auto& child : parent->fChildren) { if (!this->parseObject(child, markupDef)) { @@ -1275,36 +1437,36 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) { switch (child->fKeyWord) { case KeyWord::kClass: if (!this->parseClass(child, IsStruct::kNo)) { - return this->reportError<bool>("failed to parse class"); + return false; } break; case KeyWord::kEnum: if (!this->parseEnum(child, markupDef)) { - return this->reportError<bool>("failed to parse enum"); + return child->reportError<bool>("failed to parse enum"); } break; case KeyWord::kStruct: if (!this->parseClass(child, IsStruct::kYes)) { - return this->reportError<bool>("failed to parse struct"); + return child->reportError<bool>("failed to parse struct"); } break; case KeyWord::kTemplate: if (!this->parseTemplate()) { - return this->reportError<bool>("failed to parse template"); + return child->reportError<bool>("failed to parse template"); } break; case KeyWord::kTypedef: if (!this->parseTypedef()) { - return this->reportError<bool>("failed to parse typedef"); + return child->reportError<bool>("failed to parse typedef"); } break; case KeyWord::kUnion: if (!this->parseUnion()) { - return this->reportError<bool>("failed to parse union"); + return child->reportError<bool>("failed to parse union"); } break; default: - return this->reportError<bool>("unhandled keyword"); + return child->reportError<bool>("unhandled keyword"); } break; case Definition::Type::kBracket: @@ -1313,13 +1475,24 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) { if (fLastObject) { TextParser checkDeprecated(child->fFileName, fLastObject->fTerminator + 1, child->fStart, fLastObject->fLineCount); - checkDeprecated.skipWhiteSpace(); + if (!checkDeprecated.eof()) { + checkDeprecated.skipWhiteSpace(); + if (checkDeprecated.startsWith("SK_ATTR_DEPRECATED")) { + break; + } + } + } + { + auto tokenIter = child->fParent->fTokens.begin(); + std::advance(tokenIter, child->fParentIndex); + tokenIter = std::prev(tokenIter); + TextParser checkDeprecated(&*tokenIter); if (checkDeprecated.startsWith("SK_ATTR_DEPRECATED")) { break; } } if (!this->parseMethod(child, markupDef)) { - return this->reportError<bool>("failed to parse method"); + return child->reportError<bool>("failed to parse method"); } break; case Bracket::kSlashSlash: @@ -1356,7 +1529,7 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) { break; default: preproError: - return this->reportError<bool>("unhandled preprocessor"); + return child->reportError<bool>("unhandled preprocessor"); } break; case Bracket::kAngle: @@ -1365,20 +1538,28 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) { case Bracket::kDebugCode: // todo: handle this break; + case Bracket::kSquare: { + // check to see if parent is operator, the only case we handle so far + auto prev = child->fParent->fTokens.begin(); + std::advance(prev, child->fParentIndex - 1); + if (KeyWord::kOperator != prev->fKeyWord) { + return child->reportError<bool>("expected operator overload"); + } + } break; default: - return this->reportError<bool>("unhandled bracket"); + return child->reportError<bool>("unhandled bracket"); } break; case Definition::Type::kWord: if (MarkType::kMember != child->fMarkType) { - return this->reportError<bool>("unhandled word type"); + return child->reportError<bool>("unhandled word type"); } if (!this->parseMember(child, markupDef)) { - return this->reportError<bool>("unparsable member"); + return child->reportError<bool>("unparsable member"); } break; default: - return this->reportError<bool>("unhandled type"); + return child->reportError<bool>("unhandled type"); break; } return true; @@ -1679,6 +1860,9 @@ bool IncludeParser::parseChar() { } Definition* member = &*namedIter; member->fMarkType = MarkType::kMember; + if (!member->fTerminator) { + member->fTerminator = member->fContentEnd; + } fParent->fChildren.push_back(member); for (auto nameType = baseIter; nameType != namedIter; ++nameType) { member->fChildren.push_back(&*nameType); |