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>
This commit is contained in:
Cary Clark 2017-09-19 17:39:32 -04:00 committed by Skia Commit-Bot
parent fe69f9a50a
commit 9174bda24a
3 changed files with 532 additions and 234 deletions

View File

@ -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;
}

View File

@ -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();

View File

@ -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());
this->writeTableRow(maxLen, name.substr(0, funcLen));
}
fprintf(fOut, "#Table ##" "\n");
fprintf(fOut, "#Subtopic ##" "\n");
fprintf(fOut, "" "\n");
fprintf(fOut, "#Topic ##" "\n");
fprintf(fOut, "" "\n");
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);