| /* |
| * Copyright 2018 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef includeParser_DEFINED |
| #define includeParser_DEFINED |
| |
| #include "SkString.h" |
| |
| #include "parserCommon.h" |
| |
| class BmhParser; |
| |
| struct IClassDefinition : public Definition { |
| unordered_map<string, Definition*> fConsts; |
| unordered_map<string, Definition*> fDefines; |
| unordered_map<string, Definition*> fEnums; |
| unordered_map<string, Definition*> fMembers; |
| unordered_map<string, Definition*> fMethods; |
| unordered_map<string, Definition*> fStructs; |
| unordered_map<string, Definition*> fTypedefs; |
| }; |
| |
| class IncludeParser : public ParserCommon { |
| public: |
| enum class IsStruct { |
| kNo, |
| kYes, |
| }; |
| |
| enum class Elided { |
| kNo, |
| kYes, |
| }; |
| |
| struct CheckCode { |
| enum class State { |
| kNone, |
| kClassDeclaration, |
| kConstructor, |
| kForwardDeclaration, |
| kMethod, |
| }; |
| |
| void reset() { |
| fInDebugCode = nullptr; |
| fPrivateBrace = 0; |
| fBraceCount = 0; |
| fIndent = 0; |
| fDoubleReturn = 0; |
| fState = State::kNone; |
| fPrivateProtected = false; |
| fTypedefReturn = false; |
| fSkipAPI = false; |
| fSkipInline = false; |
| fSkipWarnUnused = false; |
| fWriteReturn = false; |
| } |
| |
| const char* fInDebugCode; |
| int fPrivateBrace; |
| int fBraceCount; |
| int fIndent; |
| int fDoubleReturn; |
| State fState; |
| bool fPrivateProtected; |
| bool fTypedefReturn; |
| bool fSkipAPI; |
| bool fSkipInline; |
| bool fSkipWarnUnused; |
| bool fWriteReturn; |
| }; |
| |
| IncludeParser() : ParserCommon() |
| , fMaps { |
| { &fIConstMap, MarkType::kConst } |
| , { &fIDefineMap, MarkType::kDefine } |
| , { &fIEnumMap, MarkType::kEnum } |
| , { &fIEnumMap, MarkType::kEnumClass } |
| , { &fIStructMap, MarkType::kStruct } |
| , { &fITemplateMap, MarkType::kTemplate } |
| , { &fITypedefMap, MarkType::kTypedef } |
| , { &fIUnionMap, MarkType::kUnion } |
| } |
| { |
| this->reset(); |
| } |
| |
| ~IncludeParser() override {} |
| |
| void addKeyword(KeyWord keyWord); |
| |
| void addPunctuation(Punctuation punctuation) { |
| fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent, '\0'); |
| } |
| |
| void addWord() { |
| fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent, '\0'); |
| fIncludeWord = nullptr; |
| } |
| |
| bool advanceInclude(TextParser& i); |
| bool inAlignAs() const; |
| void checkForMissingParams(const vector<string>& methodParams, |
| const vector<string>& foundParams); |
| bool checkForWord(); |
| string className() const; |
| |
| string codeBlock(const Definition& def, bool inProgress) const { |
| return codeBlock(def.fMarkType, def.fName, inProgress); |
| } |
| |
| string codeBlock(MarkType markType, string name, bool inProgress) const { |
| if (MarkType::kClass == markType || MarkType::kStruct == markType) { |
| auto map = fIClassMap.find(name); |
| SkASSERT(fIClassMap.end() != map || inProgress); |
| return fIClassMap.end() != map ? map->second.fCode : ""; |
| } |
| if (MarkType::kConst == markType) { |
| auto map = fIConstMap.find(name); |
| SkASSERT(fIConstMap.end() != map); |
| return map->second->fCode; |
| } |
| if (MarkType::kDefine == markType) { |
| auto map = fIDefineMap.find(name); |
| SkASSERT(fIDefineMap.end() != map); |
| return map->second->fCode; |
| } |
| if (MarkType::kEnum == markType || MarkType::kEnumClass == markType) { |
| auto map = fIEnumMap.find(name); |
| SkASSERT(fIEnumMap.end() != map); |
| return map->second->fCode; |
| } |
| if (MarkType::kTypedef == markType) { |
| auto map = fITypedefMap.find(name); |
| SkASSERT(fITypedefMap.end() != map); |
| return map->second->fCode; |
| } |
| SkASSERT(0); |
| return ""; |
| } |
| |
| void codeBlockAppend(string& result, char ch) const; |
| void codeBlockSpaces(string& result, int indent) const; |
| |
| bool crossCheck(BmhParser& ); |
| IClassDefinition* defineClass(const Definition& includeDef, string className); |
| void dumpClassTokens(IClassDefinition& classDef); |
| void dumpComment(const Definition& ); |
| void dumpCommonTail(const Definition& ); |
| void dumpConst(const Definition& , string className); |
| void dumpDefine(const Definition& ); |
| void dumpEnum(const Definition& , string name); |
| bool dumpGlobals(string* globalFileName, long int* globalTell); |
| void dumpMethod(const Definition& , string className); |
| void dumpMember(const Definition& ); |
| bool dumpTokens(); |
| bool dumpTokens(string skClassName, string globalFileName, long int* globalTell); |
| void dumpTypedef(const Definition& , string className); |
| |
| string elidedCodeBlock(const Definition& ); |
| string filteredBlock(string inContents, string filterContents); |
| bool findCommentAfter(const Definition& includeDef, Definition* markupDef); |
| bool findComments(const Definition& includeDef, Definition* markupDef); |
| Definition* findIncludeObject(const Definition& includeDef, MarkType markType, |
| string typeName); |
| static KeyWord FindKey(const char* start, const char* end); |
| Definition* findMethod(const Definition& bmhDef); |
| Bracket grandParentBracket() const; |
| const Definition* include(string ) const; |
| bool isClone(const Definition& token); |
| bool isConstructor(const Definition& token, string className); |
| bool isInternalName(const Definition& token); |
| bool isMember(const Definition& token) const; |
| bool isOperator(const Definition& token); |
| bool isUndocumentable(string filename, const char* start, const char* end, int lineCount); |
| Definition* parentBracket(Definition* parent) const; |
| bool parseChar(); |
| bool parseComment(string filename, const char* start, const char* end, int lineCount, |
| Definition* markupDef, bool* undocumentedPtr); |
| bool parseClass(Definition* def, IsStruct); |
| bool parseConst(Definition* child, Definition* markupDef); |
| bool parseDefine(Definition* child, Definition* markupDef); |
| bool parseEnum(Definition* child, Definition* markupDef); |
| bool parseEnumConst(list<Definition>::iterator& tokenIter, |
| const list<Definition>::iterator& tokenEnd, Definition* markupChild); |
| |
| bool parseFromFile(const char* path) override { |
| this->reset(); |
| if (!INHERITED::parseSetup(path)) { |
| return false; |
| } |
| string name(path); |
| return this->parseInclude(name); |
| } |
| |
| bool parseInclude(string name); |
| bool parseMember(Definition* child, Definition* markupDef); |
| bool parseMethod(Definition* child, Definition* markupDef); |
| bool parseObject(Definition* child, Definition* markupDef); |
| bool parseObjects(Definition* parent, Definition* markupDef); |
| bool parseOneEnumConst(list<Definition>& constList, Definition* markupChild, bool skipWord); |
| bool parseTemplate(Definition* child, Definition* markupDef); |
| bool parseTypedef(Definition* child, Definition* markupDef); |
| bool parseUsing(); |
| bool parseUnion(); |
| |
| void popBracket() { |
| if (Definition::Type::kKeyWord == fParent->fType |
| && KeyWord::kTypename == fParent->fKeyWord) { |
| this->popObject(); |
| } |
| SkASSERT(Definition::Type::kBracket == fParent->fType); |
| this->popObject(); |
| Bracket bracket = this->topBracket(); |
| this->setBracketShortCuts(bracket); |
| } |
| |
| void pushBracket(Bracket bracket) { |
| if ("#else" == string(fChar, 5)) { |
| SkDebugf(""); |
| } |
| this->setBracketShortCuts(bracket); |
| fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent, '\0'); |
| Definition* container = &fParent->fTokens.back(); |
| this->addDefinition(container); |
| } |
| |
| bool references(const SkString& file) const; |
| |
| static void RemoveFile(const char* docs, const char* includes); |
| static void RemoveOneFile(const char* docs, const char* includesFileOrPath); |
| |
| void reset() override { |
| INHERITED::resetCommon(); |
| fRootTopic = nullptr; |
| fConstExpr = nullptr; |
| fInBrace = nullptr; |
| fIncludeWord = nullptr; |
| fLastObject = nullptr; |
| fPriorEnum = nullptr; |
| fPriorObject = nullptr; |
| fPrev = '\0'; |
| fInChar = false; |
| fInCharCommentString = false; |
| fInComment = false; |
| fInDefine = false; |
| fInEnum = false; |
| fInFunction = false; |
| fInString = false; |
| fFailed = false; |
| } |
| |
| void setBracketShortCuts(Bracket bracket) { |
| fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket; |
| fInString = Bracket::kString == bracket; |
| fInChar = Bracket::kChar == bracket; |
| fInCharCommentString = fInChar || fInComment || fInString; |
| } |
| |
| Bracket topBracket() const; |
| |
| template <typename T> |
| string uniqueName(const unordered_map<string, T>& m, string typeName) { |
| string base(typeName.size() > 0 ? typeName : "_anonymous"); |
| string name(base); |
| int anonCount = 1; |
| do { |
| auto iter = m.find(name); |
| if (iter == m.end()) { |
| return name; |
| } |
| name = base + '_'; |
| name += to_string(++anonCount); |
| } while (true); |
| // should never get here |
| return string(); |
| } |
| |
| void validate() const; |
| void writeCodeBlock(); |
| string writeCodeBlock(const Definition&, MarkType ); |
| string writeCodeBlock(TextParser& i, MarkType , int indent); |
| |
| 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, 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, string tagID, int spaces = 1) { |
| this->writeEndTag(tagType, tagID.c_str(), spaces); |
| } |
| |
| void writeIncompleteTag(const char* tagType, string tagID, int spaces = 1) { |
| this->writeString(string("#") + tagType + " " + tagID); |
| this->writeSpace(spaces); |
| this->writeString("incomplete"); |
| this->writeSpace(); |
| this->writeString("##"); |
| this->lf(1); |
| } |
| |
| void writeIncompleteTag(const char* tagType) { |
| this->writeString(string("#") + tagType + " incomplete ##"); |
| this->lf(1); |
| } |
| |
| 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, string col1) { |
| this->lf(1); |
| string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##"; |
| this->writeString(row); |
| this->lf(1); |
| } |
| |
| void writeTableRow(size_t pad1, string col1, size_t pad2, string col2) { |
| this->lf(1); |
| string row = "# " + col1 + string(pad1 - col1.length(), ' ') + " # " + |
| col2 + string(pad2 - col2.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, 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, string tagID) { |
| this->writeTag(tagType, tagID.c_str()); |
| } |
| |
| void writeTagTable(string tagType, string body) { |
| this->writeTag(tagType.c_str()); |
| this->writeSpace(1); |
| this->writeString("#"); |
| this->writeSpace(1); |
| this->writeString(body); |
| this->writeSpace(1); |
| this->writeString("##"); |
| } |
| |
| protected: |
| static void ValidateKeyWords(); |
| |
| struct DefinitionMap { |
| unordered_map<string, Definition*>* fInclude; |
| MarkType fMarkType; |
| }; |
| |
| vector<DefinitionMap> fMaps; |
| unordered_map<string, Definition> fIncludeMap; |
| list<Definition> fGlobals; |
| unordered_map<string, IClassDefinition> fIClassMap; |
| unordered_map<string, Definition*> fIConstMap; |
| unordered_map<string, Definition*> fIDefineMap; |
| unordered_map<string, Definition*> fIEnumMap; |
| unordered_map<string, Definition*> fIFunctionMap; |
| unordered_map<string, Definition*> fIStructMap; |
| unordered_map<string, Definition*> fITemplateMap; |
| unordered_map<string, Definition*> fITypedefMap; |
| unordered_map<string, Definition*> fIUnionMap; |
| CheckCode fCheck; |
| Definition* fRootTopic; |
| Definition* fConstExpr; |
| Definition* fInBrace; |
| Definition* fLastObject; |
| Definition* fPriorEnum; |
| Definition* fPriorObject; |
| int fPriorIndex; |
| const char* fIncludeWord; |
| Elided fElided; |
| char fPrev; |
| bool fInChar; |
| bool fInCharCommentString; |
| bool fInComment; |
| bool fInDefine; |
| bool fInEnum; |
| bool fInFunction; |
| bool fInString; |
| bool fFailed; |
| |
| typedef ParserCommon INHERITED; |
| }; |
| |
| #endif |