diff options
author | Cary Clark <caryclark@skia.org> | 2018-04-16 08:37:38 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-04-16 16:26:20 +0000 |
commit | 2d4bf5f288d91f8d2371c7a970bdfa70dacdd78a (patch) | |
tree | 1aa90b6825682da0963bb48c9325d6912e3923c0 /tools/bookmaker/includeParser.cpp | |
parent | ffbe93296838c3a93a87261cae7f7229b56f1f8a (diff) |
document SkColor.h
SkColor.h uses #define liberally, and has many global symbols,
two things bookmaker hasn't seen in other includes.
Revised .h -> .bmh converter to work with SkColor.h as well
as updating how .bmh indices are built.
Generated SkColor_Reference.bmh for globals, and
SkColor4f_Reference.bmh for class.
Other than the existing comments, this doesn't update the
documentation or add new examples.
Docs-Preview: https://skia.org/?cl=118985
TBR=caryclark@google.com
Bug: skia:6898
Change-Id: I5978257ee0e51319823efbe8dfc467a08c99ffe0
Reviewed-on: https://skia-review.googlesource.com/118985
Commit-Queue: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@skia.org>
Diffstat (limited to 'tools/bookmaker/includeParser.cpp')
-rw-r--r-- | tools/bookmaker/includeParser.cpp | 713 |
1 files changed, 457 insertions, 256 deletions
diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp index 033599977c..982f7b3a78 100644 --- a/tools/bookmaker/includeParser.cpp +++ b/tools/bookmaker/includeParser.cpp @@ -161,6 +161,10 @@ bool IncludeParser::checkForWord() { switch (keyWord) { // these do not link to other # directives case KeyWord::kDefine: + if (!fInBrace) { + SkASSERT(!fInDefine); + fInDefine = true; + } case KeyWord::kInclude: case KeyWord::kError: break; @@ -259,7 +263,7 @@ bool IncludeParser::crossCheck(BmhParser& bmhParser) { const Definition* def = root->find(fullName, RootDefinition::AllowParens::kYes); switch (token.fMarkType) { case MarkType::kMethod: { - if (this->internalName(token)) { + if (this->isInternalName(token)) { continue; } if (!def) { @@ -378,7 +382,7 @@ bool IncludeParser::crossCheck(BmhParser& bmhParser) { firstMember.skipWhiteSpace(); SkASSERT('k' == firstMember.peek()); const char* savePos = firstMember.fChar; - firstMember.skipToNonAlphaNum(); + firstMember.skipToNonName(); const char* wordEnd = firstMember.fChar; firstMember.fChar = savePos; const char* lastUnderscore = nullptr; @@ -499,7 +503,7 @@ bool IncludeParser::crossCheck(BmhParser& bmhParser) { } IClassDefinition* IncludeParser::defineClass(const Definition& includeDef, - const string& name) { + string name) { string className; const Definition* test = fParent; while (Definition::Type::kFileType != test->fType) { @@ -539,9 +543,7 @@ void IncludeParser::dumpClassTokens(IClassDefinition& classDef) { continue; } if (MarkType::kMember != token.fMarkType) { - this->writeString( - "# ------------------------------------------------------------------------------"); - this->lf(2); + this->writeBlockSeparator(); } switch (token.fMarkType) { case MarkType::kEnum: @@ -549,7 +551,7 @@ void IncludeParser::dumpClassTokens(IClassDefinition& classDef) { this->dumpEnum(token, token.fName); break; case MarkType::kMethod: - this->dumpMethod(token); + this->dumpMethod(token, classDef.fName); break; case MarkType::kMember: this->dumpMember(token); @@ -558,33 +560,7 @@ void IncludeParser::dumpClassTokens(IClassDefinition& classDef) { default: SkASSERT(0); } - this->lf(2); - this->writeTag("Example"); - this->lf(1); - this->writeString("// incomplete"); - this->lf(1); - this->writeEndTag(); - this->lf(2); - this->writeTag("SeeAlso"); - this->writeSpace(); - this->writeString("incomplete"); - this->lf(2); - switch (token.fMarkType) { - case MarkType::kEnum: - case MarkType::kEnumClass: - this->writeEndTag("Enum"); - break; - case MarkType::kMethod: - this->writeEndTag("Method"); - break; - case MarkType::kMember: - this->writeEndTag("Member"); - continue; - break; - default: - SkASSERT(0); - } - this->lf(2); + this->dumpCommonTail(token); } } void IncludeParser::dumpComment(const Definition& token) { @@ -751,10 +727,55 @@ void IncludeParser::dumpComment(const Definition& token) { } } -void IncludeParser::dumpEnum(const Definition& token, const string& name) { +void IncludeParser::dumpCommonTail(const Definition& token) { + this->lf(2); + this->writeTag("Example"); + this->lf(1); + this->writeString("// incomplete"); + this->lf(1); + this->writeEndTag(); + this->lf(2); + this->writeTag("SeeAlso"); + this->writeSpace(); + this->writeString("incomplete"); + this->lf(2); + this->writeEndTag(BmhParser::kMarkProps[(int) token.fMarkType].fName); + this->lf(2); +} + +void IncludeParser::dumpDefine(const Definition& token) { + this->writeTag("Define", token.fName); + this->lf(2); + this->writeTag("Code"); + this->lfAlways(1); + this->writeString("###$"); + this->lfAlways(1); + this->indentToColumn(4); + this->writeBlock(token.fTerminator - token.fStart, token.fStart); + this->lf(1); + this->indentToColumn(0); + this->writeString("$$$#"); + + this->writeEndTag(); + this->lf(2); + this->dumpComment(token); + for (auto& child : token.fTokens) { + if (MarkType::kComment == child.fMarkType) { + continue; + } + this->writeTag("Param", child.fName); + this->writeSpace(); + this->writeString("incomplete"); + this->writeSpace(); + this->writeString("##"); + this->lf(1); + } +} + +void IncludeParser::dumpEnum(const Definition& token, string name) { this->writeTag("Enum", name); this->lf(2); - this->writeString("#Code"); + this->writeTag("Code"); this->lfAlways(1); this->indentToColumn(4); this->writeString("enum"); @@ -787,7 +808,7 @@ void IncludeParser::dumpEnum(const Definition& token, const string& name) { // start here; // get comments before // or after const values - this->writeString("#Const"); + this->writeTag("Const"); this->writeSpace(); this->writeString(child->fName); TextParser val(child); @@ -827,35 +848,203 @@ void IncludeParser::dumpEnum(const Definition& token, const string& name) { 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;"); +bool IncludeParser::dumpGlobals() { + size_t lastBSlash = fFileName.rfind('\\'); + size_t lastSlash = fFileName.rfind('/'); + size_t lastDotH = fFileName.rfind(".h"); + SkASSERT(string::npos != lastDotH); + if (string::npos != lastBSlash && (string::npos == lastSlash + || lastBSlash < lastSlash)) { + lastSlash = lastBSlash; + } else if (string::npos == lastSlash) { + lastSlash = -1; + } + lastSlash += 1; + string globalsName = fFileName.substr(lastSlash, lastDotH - lastSlash); + string fileName = globalsName + "_Reference.bmh"; + fOut = fopen(fileName.c_str(), "wb"); + if (!fOut) { + SkDebugf("could not open output file %s\n", globalsName.c_str()); + return false; + } + string prefixName = globalsName.substr(0, 2); + string topicName = globalsName.length() > 2 && isupper(globalsName[2]) && + ("Sk" == prefixName || "Gr" == prefixName) ? globalsName.substr(2) : globalsName; + this->writeTagNoLF("Topic", topicName); + this->writeTag("Alias", topicName + "_Reference"); + this->lf(2); + this->writeTag("Subtopic", "Overview"); + fIndent += 4; + this->writeTag("Subtopic", "Subtopic"); + fIndent += 4; + this->writeTag("Populate"); + fIndent -= 4; + this->writeEndTag(); + fIndent -= 4; + this->writeEndTag(); + this->lf(2); + if (!fIDefineMap.empty()) { + this->writeTag("Subtopic", "Define"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); - this->writeEndTag("DefinedBy", "void toString(SkString* str) const;"); + } + if (!fIFunctionMap.empty()) { + this->writeTag("Subtopic", "Function"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); - this->writeTag("Private"); - this->lf(1); - this->writeString("macro expands to: void toString(SkString* str) const;"); + } + if (!fIEnumMap.empty()) { + this->writeTag("Subtopic", "Enum"); + this->writeTag("Populate"); 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); + } + if (!fITemplateMap.empty()) { + this->writeTag("Subtopic", "Template"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); - this->writeTag("Param", "str"); - this->writeSpace(2); - this->writeString("storage for string representation"); - this->writeSpace(); - this->writeString("##"); + } + if (!fITypedefMap.empty()) { + this->writeTag("Subtopic", "Typedef"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); - return; } - this->writeBlock(token.length(), token.fStart); - this->lf(1); + if (!fIUnionMap.empty()) { + this->writeTag("Subtopic", "Union"); + this->writeTag("Populate"); + this->writeEndTag(); + this->lf(2); + } + std::map<int, Definition*> sortedDefs; + for (const auto& entry : fIDefineMap) { + sortedDefs[entry.second->fLineCount] = entry.second; + } + for (const auto& entry : fIFunctionMap) { + sortedDefs[entry.second->fLineCount] = entry.second; + } + for (const auto& entry : fIEnumMap) { + sortedDefs[entry.second->fLineCount] = entry.second; + } + for (const auto& entry : fITemplateMap) { + sortedDefs[entry.second->fLineCount] = entry.second; + } + for (const auto& entry : fITypedefMap) { + sortedDefs[entry.second->fLineCount] = entry.second; + } + for (const auto& entry : fIUnionMap) { + sortedDefs[entry.second->fLineCount] = entry.second; + } + for (const auto& entry : sortedDefs) { + const Definition* def = entry.second; + this->writeBlockSeparator(); + switch (def->fMarkType) { + case MarkType::kDefine: + this->dumpDefine(*def); + break; + case MarkType::kMethod: + this->dumpMethod(*def, globalsName); + break; + case MarkType::kEnum: + case MarkType::kEnumClass: + this->dumpEnum(*def, globalsName); + break; + case MarkType::kTemplate: + SkASSERT(0); // incomplete + break; + case MarkType::kTypedef: { + this->writeTag("Typedef"); + this->writeSpace(); + TextParser parser(def); + if (!parser.skipExact("typedef")) { + return false; + } + if (!parser.skipSpace()) { + return false; + } + this->writeBlock(parser.fEnd - parser.fChar, parser.fChar); + this->lf(2); + this->dumpComment(*def); + this->writeEndTag(BmhParser::kMarkProps[(int) entry.second->fMarkType].fName); + this->lf(2); + } continue; + case MarkType::kUnion: + SkASSERT(0); // incomplete + break; + default: + SkASSERT(0); + } + this->dumpCommonTail(*def); + } + this->writeEndTag("Topic", topicName); + this->lfAlways(1); + fclose(fOut); + SkDebugf("wrote %s\n", fileName.c_str()); + return true; +} + +bool IncludeParser::isClone(const Definition& token) { + string name = token.fName; + return name[name.length() - 2] == '_' && isdigit(name[name.length() - 1]); +} + +bool IncludeParser::isConstructor(const Definition& token, string className) { + string name = token.fName; + return 0 == name.find(className) || '~' == name[0]; +} + +bool IncludeParser::isInternalName(const Definition& token) { + string name = token.fName; + // exception for this SkCanvas function .. for now + if (0 == token.fName.find("androidFramework_setDeviceClipRestriction")) { + return false; + } + return name.substr(0, 7) == "android" + || 0 == token.fName.find("internal_") + || 0 == token.fName.find("Internal_") + || 0 == token.fName.find("legacy_") + || 0 == token.fName.find("temporary_") + || 0 == token.fName.find("private_"); +} + +bool IncludeParser::isOperator(const Definition& token) { + return "operator" == token.fName.substr(0, 8); +} + +void IncludeParser::dumpMethod(const Definition& token, string className) { + this->writeTag("Method"); + this->writeSpace(); + + string name = string(token.fStart ? token.fStart : token.fContentStart, + token.length()); + if (this->isOperator(token)) { + string spaceConst(" const"); + size_t constPos = name.rfind(spaceConst); + if (name.length() - spaceConst.length() == constPos) { + name = name.substr(0, constPos) + "_const"; + } + } + this->writeString(name); + string inType; + if (this->isConstructor(token, className)) { + inType = "Constructor"; + } else if (this->isOperator(token)) { + inType = "Operator"; + } else { + inType = "incomplete"; + } + this->writeTag("In", inType); + this->writeTag("Line"); + this->writeSpace(1); + this->writeString("#"); + this->writeSpace(1); + this->writeString("incomplete"); + this->writeSpace(1); + this->writeString("##"); + this->lf(2); this->dumpComment(token); } @@ -871,12 +1060,15 @@ void IncludeParser::dumpMember(const Definition& token) { lf(2); } -bool IncludeParser::dumpTokens(const string& dir) { +bool IncludeParser::dumpTokens() { + if (!this->dumpGlobals()) { + return false; + } for (const auto& member : fIClassMap) { if (string::npos != member.first.find("::")) { continue; } - if (!this->dumpTokens(dir, member.first)) { + if (!this->dumpTokens(member.first)) { return false; } } @@ -884,12 +1076,8 @@ bool IncludeParser::dumpTokens(const string& dir) { } // dump equivalent markup -bool IncludeParser::dumpTokens(const string& dir, const string& skClassName) { - string fileName = dir; - if (dir.length() && '/' != dir[dir.length() - 1]) { - fileName += '/'; - } - fileName += skClassName + "_Reference.bmh"; +bool IncludeParser::dumpTokens(string skClassName) { + string fileName = skClassName + "_Reference.bmh"; fOut = fopen(fileName.c_str(), "wb"); if (!fOut) { SkDebugf("could not open output file %s\n", fileName.c_str()); @@ -915,160 +1103,82 @@ bool IncludeParser::dumpTokens(const string& dir, const string& skClassName) { this->lf(1); } this->lf(2); - string className(skClassName.substr(2)); - vector<string> classNames; - vector<string> constNames; - vector<string> constructorNames; - vector<string> memberNames; - vector<string> operatorNames; - size_t classMaxLen = 0; - size_t constMaxLen = 0; - size_t constructorMaxLen = 0; - size_t memberMaxLen = 0; - size_t operatorMaxLen = 0; + bool hasClass = false; + bool hasConst = !fIEnumMap.empty(); + bool hasConstructor = false; + bool hasMember = false; + bool hasOperator = false; for (const auto& oneClass : fIClassMap) { if (skClassName + "::" != oneClass.first.substr(0, skClassName.length() + 2)) { continue; } - string structName = oneClass.first.substr(skClassName.length() + 2); - classMaxLen = SkTMax(classMaxLen, structName.length()); - classNames.emplace_back(structName); - } - for (const auto& oneEnum : fIEnumMap) { - string enumName = oneEnum.first; - constMaxLen = SkTMax(constMaxLen, enumName.length()); - constNames.emplace_back(enumName); + hasClass = true; + break; } for (const auto& token : classMap.fTokens) { if (Definition::Type::kMark != token.fType || MarkType::kMethod != token.fMarkType) { continue; } - string name = token.fName; - if (name.substr(0, 7) == "android" || string::npos != name.find("nternal_")) { + if (this->isInternalName(token)) { continue; } - if ((name.substr(0, 2) == "Sk" && 2 == name.find(className)) || '~' == name[0]) { - name = string(token.fContentStart, (int) (token.fContentEnd - token.fContentStart)); - constructorMaxLen = SkTMax(constructorMaxLen, name.length()); - constructorNames.emplace_back(name); + if (this->isConstructor(token, skClassName)) { + hasConstructor = true; continue; } - if (name.substr(0, 8) == "operator") { - name = string(token.fContentStart, (int) (token.fContentEnd - token.fContentStart)); - operatorMaxLen = SkTMax(operatorMaxLen, name.length()); - operatorNames.emplace_back(name); + if (this->isOperator(token)) { + hasOperator = true; continue; } - if (name[name.length() - 2] == '_' && isdigit(name[name.length() - 1])) { + if (this->isClone(token)) { continue; } - if ("SK_TO_STRING_NONVIRT" == name) { - name = "toString"; - } - size_t paren = name.find('('); - size_t funcLen = string::npos == paren ? name.length() : paren; - memberMaxLen = SkTMax(memberMaxLen, funcLen); - memberNames.emplace_back(name); + hasMember = true; } - this->writeTag("Topic", "Overview"); - this->lf(2); - this->writeTag("Subtopic", "Subtopics"); - string classesName = classMaxLen ? "Classes_and_Structs" : ""; - string constsName = constructorMaxLen ? "Constants" : ""; - string constructorsName = constructorMaxLen ? "Constructors" : ""; - string membersName = memberMaxLen ? "Member_Functions" : ""; - string operatorsName = operatorMaxLen ? "Operators" : ""; - size_t nameLen = SkTMax(classesName.size(), SkTMax(constsName.size(), - SkTMax(constructorsName.size(), SkTMax(membersName.size(), operatorsName.size())))); - this->writeTableHeader("name", nameLen, "description"); - string classDesc = classMaxLen ? "embedded struct and class members" : ""; - string constDesc = constMaxLen ? "enum and enum class, const values" : ""; - string constructorDesc = constructorMaxLen ? "functions that construct " + className : ""; - string memberDesc = memberMaxLen ? "static functions and member methods" : ""; - string operatorDesc = operatorMaxLen ? "operator overloading methods" : ""; - size_t descLen = SkTMax(classDesc.size(), SkTMax(constDesc.size(), SkTMax(constructorDesc.size(), - SkTMax(memberDesc.size(), operatorDesc.size())))); - if (classMaxLen) { - this->writeTableRow(nameLen, classesName, descLen, classDesc); - } - if (constMaxLen) { - this->writeTableRow(nameLen, constsName, descLen, constDesc); - } - if (constructorMaxLen) { - this->writeTableRow(nameLen, constructorsName, descLen, constructorDesc); - } - if (memberMaxLen) { - this->writeTableRow(nameLen, membersName, descLen, memberDesc); - } - if (operatorMaxLen) { - this->writeTableRow(nameLen, operatorsName, descLen, operatorDesc); - } - this->writeTableTrailer(); + this->writeTag("Subtopic", "Overview"); + fIndent += 4; + this->writeTag("Subtopic", "Subtopic"); + fIndent += 4; + this->writeTag("Populate"); + fIndent -= 4; + this->writeEndTag(); + fIndent -= 4; this->writeEndTag(); this->lf(2); - if (classMaxLen) { - std::sort(classNames.begin(), classNames.end()); - this->writeTag("Subtopic", "Classes_and_Structs"); - this->writeTableHeader("name", classMaxLen, "description"); - for (auto& name : classNames) { - this->writeTableRow(classMaxLen, name); - } - this->writeTableTrailer(); - this->writeEndTag("Subtopic"); + + if (hasClass) { + this->writeTag("Subtopic", "Class_or_Struct"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); } - if (constMaxLen) { - std::sort(constNames.begin(), constNames.end()); - this->writeTag("Subtopic", "Constants"); - this->writeTableHeader("name", constMaxLen, "description"); - for (auto& name : constNames) { - this->writeTableRow(constMaxLen, name); - } - this->writeTableTrailer(); - this->writeEndTag("Subtopic"); + if (hasConst) { + this->writeTag("Subtopic", "Constant"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); } - if (constructorMaxLen) { - std::sort(constructorNames.begin(), constructorNames.end()); - this->writeTag("Subtopic", "Constructors"); - this->writeTableHeader("name", constructorMaxLen, "description"); - for (auto& name : constructorNames) { - this->writeTableRow(constructorMaxLen, name); - } - this->writeTableTrailer(); - this->writeEndTag("Subtopic"); + if (hasConstructor) { + this->writeTag("Subtopic", "Constructor"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); } - if (operatorMaxLen) { - std::sort(operatorNames.begin(), operatorNames.end()); - this->writeTag("Subtopic", "Operators"); - this->writeTableHeader("name", operatorMaxLen, "description"); - for (auto& name : operatorNames) { - this->writeTableRow(operatorMaxLen, name); - } - this->writeTableTrailer(); - this->writeEndTag("Subtopic"); + if (hasOperator) { + this->writeTag("Subtopic", "Operator"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); } - if (memberMaxLen) { - std::sort(memberNames.begin(), memberNames.end()); - this->writeTag("Subtopic", "Member_Functions"); - this->writeTableHeader("name", memberMaxLen, "description"); - for (auto& name : memberNames) { - size_t paren = name.find('('); - size_t funcLen = string::npos == paren ? name.length() : paren; - this->writeTableRow(memberMaxLen, name.substr(0, funcLen)); - } - this->writeTableTrailer(); - this->writeEndTag("Subtopic"); + if (hasMember) { + this->writeTag("Subtopic", "Member_Function"); + this->writeTag("Populate"); + this->writeEndTag(); this->lf(2); } - this->writeEndTag("Topic"); - this->lf(2); for (auto& oneEnum : fIEnumMap) { - this->writeString( - "# ------------------------------------------------------------------------------"); - this->dumpEnum(oneEnum.second, oneEnum.first); + this->writeBlockSeparator(); + this->dumpEnum(*oneEnum.second, oneEnum.first); this->lf(2); this->writeTag("Example"); this->lfcr(); @@ -1085,9 +1195,7 @@ bool IncludeParser::dumpTokens(const string& dir, const string& skClassName) { continue; } string innerName = oneClass.first.substr(skClassName.length() + 2); - this->writeString( - "# ------------------------------------------------------------------------------"); - this->lf(2); + this->writeBlockSeparator(); KeyWord keyword = oneClass.second.fKeyWord; SkASSERT(KeyWord::kClass == keyword || KeyWord::kStruct == keyword); const char* containerType = KeyWord::kClass == keyword ? "Class" : "Struct"; @@ -1159,14 +1267,6 @@ bool IncludeParser::findComments(const Definition& includeDef, Definition* marku return true; } -bool IncludeParser::internalName(const Definition& token) const { - return 0 == token.fName.find("internal_") - || 0 == token.fName.find("Internal_") - || 0 == token.fName.find("legacy_") - || 0 == token.fName.find("temporary_") - || 0 == token.fName.find("private_"); -} - // caller calls reportError, so just return false here bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) { SkASSERT(includeDef->fTokens.size() > 0); @@ -1267,7 +1367,7 @@ bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) { return true; } -bool IncludeParser::parseComment(const string& filename, const char* start, const char* end, +bool IncludeParser::parseComment(string filename, const char* start, const char* end, int lineCount, Definition* markupDef) { TextParser parser(filename, start, end, lineCount); // parse doxygen if present @@ -1277,14 +1377,26 @@ bool IncludeParser::parseComment(const string& filename, const char* start, cons parser.skipWhiteSpace(); if ('\\' == parser.peek()) { parser.next(); - if (!parser.skipWord(kKeyWords[(int) markupDef->fKeyWord].fName)) { - return reportError<bool>("missing object type"); - } - if (!parser.skipWord(markupDef->fName.c_str()) && - KeyWord::kEnum != markupDef->fKeyWord) { - return reportError<bool>("missing object name"); + // Doxygen tag may be "file" or "fn" in addition to "class", "enum", "struct" + if (parser.skipExact("file")) { + if (Definition::Type::kFileType != fParent->fType) { + return reportError<bool>("expected parent is file"); + } + string filename = markupDef->fileName(); + if (!parser.skipWord(filename.c_str())) { + return reportError<bool>("missing object type"); + } + } else if (parser.skipExact("fn")) { + SkASSERT(0); // incomplete + } else { + if (!parser.skipWord(kKeyWords[(int) markupDef->fKeyWord].fName)) { + return reportError<bool>("missing object type"); + } + if (!parser.skipWord(markupDef->fName.c_str()) && + KeyWord::kEnum != markupDef->fKeyWord) { + return reportError<bool>("missing object name"); + } } - } } // remove leading '*' if present @@ -1308,8 +1420,87 @@ bool IncludeParser::parseComment(const string& filename, const char* start, cons return true; } -bool IncludeParser::parseDefine() { - +bool IncludeParser::parseDefine(Definition* child, Definition* markupDef) { + TextParser parser(child); + if (!parser.skipExact("#define")) { + return false; + } + if (!parser.skipSpace()) { + return false; + } + const char* nameStart = parser.fChar; + parser.skipToNonAlphaNum(); // FIXME: just want to skip isalnum() and '_' + if (parser.eof()) { + return true; // do nothing if #define doesn't define anything + } + string nameStr(nameStart, parser.fChar - nameStart); + struct Param { + const char* fStart; + const char* fEnd; + }; + vector<Param> params; + if ('(' == parser.peek()) { + parser.next(); + if (!parser.skipSpace()) { + return false; + } + do { + const char* paramStart = parser.fChar; + if (!parser.skipExact("...")) { + parser.skipToNonAlphaNum(); + } + if (parser.eof()) { + return false; + } + params.push_back({paramStart, parser.fChar}); + if (!parser.skipSpace()) { + return false; + } + if (')' == parser.peek()) { + parser.next(); + break; + } + if (',' != parser.next()) { + return false; + } + if (!parser.skipSpace()) { + return false; + } + } while (true); + } + if (!parser.skipSpace()) { + return false; + } + if (!markupDef) { + fGlobals.emplace_back(MarkType::kDefine, nameStart, child->fContentEnd, + child->fLineCount, fParent, '\0'); + Definition* globalMarkupChild = &fGlobals.back(); + string globalUniqueName = this->uniqueName(fIDefineMap, nameStr); + globalMarkupChild->fName = globalUniqueName; + globalMarkupChild->fTerminator = child->fContentEnd; + if (!this->findComments(*child, globalMarkupChild)) { + return false; + } + fIDefineMap[globalUniqueName] = globalMarkupChild; + for (Param param : params) { + globalMarkupChild->fTokens.emplace_back(MarkType::kParam, param.fStart, param.fEnd, + child->fLineCount, globalMarkupChild, '\0'); + Definition* paramChild = &globalMarkupChild->fTokens.back(); + paramChild->fName = string(param.fStart, param.fEnd - param.fStart); + paramChild->fTerminator = param.fEnd; + } + return true; + } + markupDef->fTokens.emplace_back(MarkType::kDefine, child->fContentStart, child->fContentEnd, + child->fLineCount, markupDef, '\0'); + Definition* markupChild = &markupDef->fTokens.back(); + markupChild->fName = nameStr; + markupChild->fTerminator = markupChild->fContentEnd; + IClassDefinition& classDef = fIClassMap[markupDef->fName]; + if (!this->findComments(*child, markupChild)) { + return false; + } + classDef.fDefines[nameStr] = markupChild; return true; } @@ -1332,17 +1523,13 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) { } Definition* markupChild; if (!markupDef) { - auto finder = fIEnumMap.find(nameStr); - if (fIEnumMap.end() != finder) { - return child->reportError<bool>("duplicate global enum name"); - } - markupChild = &fIEnumMap[nameStr]; - markupChild->fContentStart = child->fContentStart; - markupChild->fName = nameStr; - markupChild->fFiddle = nameStr; - markupChild->fContentEnd = child->fContentEnd; - markupChild->fFileName = child->fFileName; - markupChild->fLineCount = child->fLineCount; + fGlobals.emplace_back(MarkType::kEnum, child->fContentStart, child->fContentEnd, + child->fLineCount, fParent, '\0'); + markupChild = &fGlobals.back(); + string globalUniqueName = this->uniqueName(fIEnumMap, nameStr); + markupChild->fName = globalUniqueName; + markupChild->fTerminator = child->fContentEnd; + fIEnumMap[globalUniqueName] = markupChild; } else { markupDef->fTokens.emplace_back(MarkType::kEnum, child->fContentStart, child->fContentEnd, child->fLineCount, markupDef, '\0'); @@ -1407,7 +1594,7 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) { } // if there's comment on same the line as member def, output first as if it was before - parser.skipToNonAlphaNum(); + parser.skipToNonName(); string memberName(memberStart, parser.fChar); if (parser.eof() || !parser.skipWhiteSpace()) { return this->reportError<bool>("enum member must end with comma 1"); @@ -1486,7 +1673,7 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) { return true; } -bool IncludeParser::parseInclude(const string& name) { +bool IncludeParser::parseInclude(string name) { fParent = &fIncludeMap[name]; fParent->fName = name; fParent->fFileName = fFileName; @@ -1513,7 +1700,7 @@ bool IncludeParser::parseMember(Definition* child, Definition* markupDef) { child->fLineCount, markupDef, '\0'); Definition* markupChild = &markupDef->fTokens.back(); TextParser nameParser(child); - nameParser.skipToNonAlphaNum(); + nameParser.skipToNonName(); string nameStr = string(child->fContentStart, nameParser.fChar - child->fContentStart); IClassDefinition& classDef = fIClassMap[markupDef->fName]; string uniqueName = this->uniqueName(classDef.fMethods, nameStr); @@ -1667,19 +1854,15 @@ bool IncludeParser::parseMethod(Definition* child, Definition* markupDef) { if (nameParser.skipToEndBracket(':') && nameParser.startsWith("::")) { return true; // expect this is inline class definition outside of class } - string name(nameParser.fLine, nameParser.lineLength()); - auto finder = fIFunctionMap.find(name); - if (fIFunctionMap.end() != finder) { - // create unique name - SkASSERT(0); // incomplete - } - auto globalFunction = &fIFunctionMap[name]; - globalFunction->fContentStart = start; - globalFunction->fName = name; - globalFunction->fFiddle = name; - globalFunction->fContentEnd = end; - globalFunction->fMarkType = MarkType::kMethod; - globalFunction->fLineCount = tokenIter->fLineCount; + fGlobals.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount, + fParent, '\0'); + Definition* globalMarkupChild = &fGlobals.back(); + string globalUniqueName = this->uniqueName(fIFunctionMap, nameStr); + globalMarkupChild->fName = globalUniqueName; + if (!this->findComments(*child, globalMarkupChild)) { + return false; + } + fIFunctionMap[globalUniqueName] = globalMarkupChild; return true; } markupDef->fTokens.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount, @@ -1799,7 +1982,7 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) { case KeyWord::kIf: case KeyWord::kIfndef: case KeyWord::kIfdef: - if (child->boilerplateIfDef(fParent)) { + if (child->boilerplateIfDef()) { if (!this->parseObjects(child, markupDef)) { return false; } @@ -1807,7 +1990,7 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) { } goto preproError; case KeyWord::kDefine: - if (child->boilerplateDef(fParent)) { + if (this->parseDefine(child, markupDef)) { break; } goto preproError; @@ -1873,16 +2056,15 @@ bool IncludeParser::parseTypedef(Definition* child, Definition* markupDef) { typedefParser.skipWhiteSpace(); string nameStr = typedefParser.typedefName(); if (!markupDef) { - Definition& typedefDef = fITypedefMap[nameStr]; - SkASSERT(!typedefDef.fStart); - typedefDef.fStart = child->fContentStart; - typedefDef.fContentStart = child->fContentStart; - typedefDef.fName = nameStr; - typedefDef.fFiddle = nameStr; - typedefDef.fContentEnd = child->fContentEnd; - typedefDef.fTerminator = child->fContentEnd; - typedefDef.fMarkType = MarkType::kTypedef; - typedefDef.fLineCount = child->fLineCount; + fGlobals.emplace_back(MarkType::kTypedef, child->fContentStart, child->fContentEnd, + child->fLineCount, fParent, '\0'); + Definition* globalMarkupChild = &fGlobals.back(); + string globalUniqueName = this->uniqueName(fITypedefMap, nameStr); + globalMarkupChild->fName = globalUniqueName; + if (!this->findComments(*child, globalMarkupChild)) { + return false; + } + fITypedefMap[globalUniqueName] = globalMarkupChild; return true; } markupDef->fTokens.emplace_back(MarkType::kTypedef, child->fContentStart, child->fContentEnd, @@ -1927,9 +2109,17 @@ bool IncludeParser::parseChar() { if (KeyWord::kNone == keyWord) { return this->reportError<bool>("unhandled preprocessor directive"); } + if (fInDefine) { + SkASSERT(KeyWord::kDefine == keyWord); + fInDefine = false; + } if (KeyWord::kInclude == keyWord || KeyWord::kDefine == keyWord || KeyWord::kError == keyWord) { this->popBracket(); } + if (fInBrace) { + SkASSERT(KeyWord::kDefine == fInBrace->fKeyWord); + fInBrace = nullptr; + } } else if (Bracket::kSlashSlash == this->topBracket()) { this->popBracket(); } @@ -1986,18 +2176,21 @@ bool IncludeParser::parseChar() { this->pushBracket(Bracket::kString); } break; - case ':': case '(': - case '[': - case '{': { - if (fIncludeWord && '(' == test && fChar - fIncludeWord >= 10 && + if (fIncludeWord && fChar - fIncludeWord >= 10 && !strncmp("SkDEBUGCODE", fIncludeWord, 10)) { this->pushBracket(Bracket::kDebugCode); break; } + case ':': + case '[': + case '{': { if (fInCharCommentString) { break; } + if (fInDefine && fInBrace) { + break; + } if (':' == test && (fInBrace || ':' == fChar[-1] || ':' == fChar[1])) { break; } @@ -2051,6 +2244,9 @@ bool IncludeParser::parseChar() { if (fInCharCommentString) { break; } + if (fInDefine && fInBrace) { + break; + } if (!fInBrace) { if (!this->checkForWord()) { return false; @@ -2104,9 +2300,14 @@ bool IncludeParser::parseChar() { this->pushBracket(Bracket::kPound); break; } + case ' ': + if (fInDefine && !fInBrace && Bracket::kPound == this->topBracket()) { + SkASSERT(KeyWord::kDefine == fParent->fKeyWord); + fInBrace = fParent; + // delimiting brackets are space ... unescaped-linefeed + } case '&': case ',': - case ' ': case '+': case '=': case '-': @@ -2260,7 +2461,7 @@ bool IncludeParser::parseChar() { std::advance(tokenWalker, 1); if (tokenWalker != fParent->fTokens.end()) { TextParser tp(fFileName, nameStart, tokenWalker->fStart, fLineCount); - tp.skipToNonAlphaNum(); + tp.skipToNonName(); start->fName = string(nameStart, tp.fChar - nameStart); start->fContentEnd = fChar; priorEnum->fChildren.emplace_back(start); |