Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef includeParser_DEFINED |
| 9 | #define includeParser_DEFINED |
| 10 | |
| 11 | #include "SkString.h" |
| 12 | |
| 13 | #include "parserCommon.h" |
| 14 | |
| 15 | class BmhParser; |
| 16 | |
| 17 | struct IClassDefinition : public Definition { |
| 18 | unordered_map<string, Definition*> fConsts; |
| 19 | unordered_map<string, Definition*> fDefines; |
| 20 | unordered_map<string, Definition*> fEnums; |
| 21 | unordered_map<string, Definition*> fMembers; |
| 22 | unordered_map<string, Definition*> fMethods; |
| 23 | unordered_map<string, Definition*> fStructs; |
| 24 | unordered_map<string, Definition*> fTypedefs; |
| 25 | }; |
| 26 | |
| 27 | class IncludeParser : public ParserCommon { |
| 28 | public: |
| 29 | enum class IsStruct { |
| 30 | kNo, |
| 31 | kYes, |
| 32 | }; |
| 33 | |
| 34 | enum class Elided { |
| 35 | kNo, |
| 36 | kYes, |
| 37 | }; |
| 38 | |
Cary Clark | fd32e72 | 2018-11-16 14:36:02 -0500 | [diff] [blame^] | 39 | enum class Suggest { |
| 40 | kMethodMissing, |
| 41 | kMethodDiffers, |
| 42 | }; |
| 43 | |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 44 | struct CheckCode { |
| 45 | enum class State { |
| 46 | kNone, |
| 47 | kClassDeclaration, |
| 48 | kConstructor, |
| 49 | kForwardDeclaration, |
| 50 | kMethod, |
| 51 | }; |
| 52 | |
| 53 | void reset() { |
| 54 | fInDebugCode = nullptr; |
| 55 | fPrivateBrace = 0; |
| 56 | fBraceCount = 0; |
| 57 | fIndent = 0; |
| 58 | fDoubleReturn = 0; |
| 59 | fState = State::kNone; |
| 60 | fPrivateProtected = false; |
| 61 | fTypedefReturn = false; |
| 62 | fSkipAPI = false; |
| 63 | fSkipInline = false; |
| 64 | fSkipWarnUnused = false; |
| 65 | fWriteReturn = false; |
| 66 | } |
| 67 | |
| 68 | const char* fInDebugCode; |
| 69 | int fPrivateBrace; |
| 70 | int fBraceCount; |
| 71 | int fIndent; |
| 72 | int fDoubleReturn; |
| 73 | State fState; |
| 74 | bool fPrivateProtected; |
| 75 | bool fTypedefReturn; |
| 76 | bool fSkipAPI; |
| 77 | bool fSkipInline; |
| 78 | bool fSkipWarnUnused; |
| 79 | bool fWriteReturn; |
| 80 | }; |
| 81 | |
| 82 | IncludeParser() : ParserCommon() |
| 83 | , fMaps { |
| 84 | { &fIConstMap, MarkType::kConst } |
| 85 | , { &fIDefineMap, MarkType::kDefine } |
| 86 | , { &fIEnumMap, MarkType::kEnum } |
| 87 | , { &fIEnumMap, MarkType::kEnumClass } |
| 88 | , { &fIStructMap, MarkType::kStruct } |
| 89 | , { &fITemplateMap, MarkType::kTemplate } |
| 90 | , { &fITypedefMap, MarkType::kTypedef } |
| 91 | , { &fIUnionMap, MarkType::kUnion } |
| 92 | } |
| 93 | { |
| 94 | this->reset(); |
| 95 | } |
| 96 | |
| 97 | ~IncludeParser() override {} |
| 98 | |
| 99 | void addKeyword(KeyWord keyWord); |
| 100 | |
| 101 | void addPunctuation(Punctuation punctuation) { |
| 102 | fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent, '\0'); |
| 103 | } |
| 104 | |
| 105 | void addWord() { |
| 106 | fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent, '\0'); |
| 107 | fIncludeWord = nullptr; |
| 108 | } |
| 109 | |
| 110 | bool advanceInclude(TextParser& i); |
| 111 | bool inAlignAs() const; |
| 112 | void checkForMissingParams(const vector<string>& methodParams, |
| 113 | const vector<string>& foundParams); |
| 114 | bool checkForWord(); |
Cary Clark | fd32e72 | 2018-11-16 14:36:02 -0500 | [diff] [blame^] | 115 | void checkTokens(list<Definition>& tokens, string key, string className, |
| 116 | RootDefinition* root, BmhParser& bmhParser); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 117 | string className() const; |
| 118 | |
| 119 | string codeBlock(const Definition& def, bool inProgress) const { |
| 120 | return codeBlock(def.fMarkType, def.fName, inProgress); |
| 121 | } |
| 122 | |
| 123 | string codeBlock(MarkType markType, string name, bool inProgress) const { |
| 124 | if (MarkType::kClass == markType || MarkType::kStruct == markType) { |
| 125 | auto map = fIClassMap.find(name); |
| 126 | SkASSERT(fIClassMap.end() != map || inProgress); |
| 127 | return fIClassMap.end() != map ? map->second.fCode : ""; |
| 128 | } |
| 129 | if (MarkType::kConst == markType) { |
| 130 | auto map = fIConstMap.find(name); |
| 131 | SkASSERT(fIConstMap.end() != map); |
| 132 | return map->second->fCode; |
| 133 | } |
| 134 | if (MarkType::kDefine == markType) { |
| 135 | auto map = fIDefineMap.find(name); |
| 136 | SkASSERT(fIDefineMap.end() != map); |
| 137 | return map->second->fCode; |
| 138 | } |
| 139 | if (MarkType::kEnum == markType || MarkType::kEnumClass == markType) { |
| 140 | auto map = fIEnumMap.find(name); |
| 141 | SkASSERT(fIEnumMap.end() != map); |
| 142 | return map->second->fCode; |
| 143 | } |
| 144 | if (MarkType::kTypedef == markType) { |
| 145 | auto map = fITypedefMap.find(name); |
| 146 | SkASSERT(fITypedefMap.end() != map); |
| 147 | return map->second->fCode; |
| 148 | } |
| 149 | SkASSERT(0); |
| 150 | return ""; |
| 151 | } |
| 152 | |
| 153 | void codeBlockAppend(string& result, char ch) const; |
| 154 | void codeBlockSpaces(string& result, int indent) const; |
| 155 | |
| 156 | bool crossCheck(BmhParser& ); |
| 157 | IClassDefinition* defineClass(const Definition& includeDef, string className); |
| 158 | void dumpClassTokens(IClassDefinition& classDef); |
| 159 | void dumpComment(const Definition& ); |
| 160 | void dumpCommonTail(const Definition& ); |
| 161 | void dumpConst(const Definition& , string className); |
| 162 | void dumpDefine(const Definition& ); |
| 163 | void dumpEnum(const Definition& , string name); |
| 164 | bool dumpGlobals(string* globalFileName, long int* globalTell); |
| 165 | void dumpMethod(const Definition& , string className); |
| 166 | void dumpMember(const Definition& ); |
| 167 | bool dumpTokens(); |
| 168 | bool dumpTokens(string skClassName, string globalFileName, long int* globalTell); |
| 169 | void dumpTypedef(const Definition& , string className); |
| 170 | |
| 171 | string elidedCodeBlock(const Definition& ); |
| 172 | string filteredBlock(string inContents, string filterContents); |
Cary Clark | abaffd8 | 2018-11-15 08:25:12 -0500 | [diff] [blame] | 173 | bool findCommentAfter(const Definition& includeDef, Definition* markupDef); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 174 | bool findComments(const Definition& includeDef, Definition* markupDef); |
| 175 | Definition* findIncludeObject(const Definition& includeDef, MarkType markType, |
| 176 | string typeName); |
| 177 | static KeyWord FindKey(const char* start, const char* end); |
| 178 | Definition* findMethod(const Definition& bmhDef); |
| 179 | Bracket grandParentBracket() const; |
| 180 | const Definition* include(string ) const; |
| 181 | bool isClone(const Definition& token); |
| 182 | bool isConstructor(const Definition& token, string className); |
| 183 | bool isInternalName(const Definition& token); |
| 184 | bool isMember(const Definition& token) const; |
| 185 | bool isOperator(const Definition& token); |
Cary Clark | abaffd8 | 2018-11-15 08:25:12 -0500 | [diff] [blame] | 186 | bool isUndocumentable(string filename, const char* start, const char* end, int lineCount); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 187 | Definition* parentBracket(Definition* parent) const; |
| 188 | bool parseChar(); |
| 189 | bool parseComment(string filename, const char* start, const char* end, int lineCount, |
Cary Clark | abaffd8 | 2018-11-15 08:25:12 -0500 | [diff] [blame] | 190 | Definition* markupDef, bool* undocumentedPtr); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 191 | bool parseClass(Definition* def, IsStruct); |
| 192 | bool parseConst(Definition* child, Definition* markupDef); |
| 193 | bool parseDefine(Definition* child, Definition* markupDef); |
| 194 | bool parseEnum(Definition* child, Definition* markupDef); |
Cary Clark | abaffd8 | 2018-11-15 08:25:12 -0500 | [diff] [blame] | 195 | bool parseEnumConst(list<Definition>::iterator& tokenIter, |
| 196 | const list<Definition>::iterator& tokenEnd, Definition* markupChild); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 197 | |
| 198 | bool parseFromFile(const char* path) override { |
| 199 | this->reset(); |
| 200 | if (!INHERITED::parseSetup(path)) { |
| 201 | return false; |
| 202 | } |
| 203 | string name(path); |
| 204 | return this->parseInclude(name); |
| 205 | } |
| 206 | |
| 207 | bool parseInclude(string name); |
| 208 | bool parseMember(Definition* child, Definition* markupDef); |
| 209 | bool parseMethod(Definition* child, Definition* markupDef); |
| 210 | bool parseObject(Definition* child, Definition* markupDef); |
| 211 | bool parseObjects(Definition* parent, Definition* markupDef); |
Cary Clark | abaffd8 | 2018-11-15 08:25:12 -0500 | [diff] [blame] | 212 | bool parseOneEnumConst(list<Definition>& constList, Definition* markupChild, bool skipWord); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 213 | bool parseTemplate(Definition* child, Definition* markupDef); |
| 214 | bool parseTypedef(Definition* child, Definition* markupDef); |
| 215 | bool parseUsing(); |
| 216 | bool parseUnion(); |
| 217 | |
| 218 | void popBracket() { |
| 219 | if (Definition::Type::kKeyWord == fParent->fType |
| 220 | && KeyWord::kTypename == fParent->fKeyWord) { |
| 221 | this->popObject(); |
| 222 | } |
| 223 | SkASSERT(Definition::Type::kBracket == fParent->fType); |
| 224 | this->popObject(); |
| 225 | Bracket bracket = this->topBracket(); |
| 226 | this->setBracketShortCuts(bracket); |
| 227 | } |
| 228 | |
| 229 | void pushBracket(Bracket bracket) { |
Cary Clark | abaffd8 | 2018-11-15 08:25:12 -0500 | [diff] [blame] | 230 | if ("#else" == string(fChar, 5)) { |
| 231 | SkDebugf(""); |
| 232 | } |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 233 | this->setBracketShortCuts(bracket); |
| 234 | fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent, '\0'); |
| 235 | Definition* container = &fParent->fTokens.back(); |
| 236 | this->addDefinition(container); |
| 237 | } |
| 238 | |
| 239 | bool references(const SkString& file) const; |
| 240 | |
| 241 | static void RemoveFile(const char* docs, const char* includes); |
| 242 | static void RemoveOneFile(const char* docs, const char* includesFileOrPath); |
| 243 | |
| 244 | void reset() override { |
| 245 | INHERITED::resetCommon(); |
| 246 | fRootTopic = nullptr; |
| 247 | fConstExpr = nullptr; |
| 248 | fInBrace = nullptr; |
| 249 | fIncludeWord = nullptr; |
| 250 | fLastObject = nullptr; |
| 251 | fPriorEnum = nullptr; |
| 252 | fPriorObject = nullptr; |
| 253 | fPrev = '\0'; |
| 254 | fInChar = false; |
| 255 | fInCharCommentString = false; |
| 256 | fInComment = false; |
| 257 | fInDefine = false; |
| 258 | fInEnum = false; |
| 259 | fInFunction = false; |
| 260 | fInString = false; |
| 261 | fFailed = false; |
| 262 | } |
| 263 | |
| 264 | void setBracketShortCuts(Bracket bracket) { |
| 265 | fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket; |
| 266 | fInString = Bracket::kString == bracket; |
| 267 | fInChar = Bracket::kChar == bracket; |
| 268 | fInCharCommentString = fInChar || fInComment || fInString; |
| 269 | } |
| 270 | |
Cary Clark | fd32e72 | 2018-11-16 14:36:02 -0500 | [diff] [blame^] | 271 | void suggestFix(Suggest suggest, const Definition& iDef, const RootDefinition* root, |
| 272 | const Definition* bDef); |
Cary Clark | 2da9fb8 | 2018-11-01 09:29:36 -0400 | [diff] [blame] | 273 | Bracket topBracket() const; |
| 274 | |
| 275 | template <typename T> |
| 276 | string uniqueName(const unordered_map<string, T>& m, string typeName) { |
| 277 | string base(typeName.size() > 0 ? typeName : "_anonymous"); |
| 278 | string name(base); |
| 279 | int anonCount = 1; |
| 280 | do { |
| 281 | auto iter = m.find(name); |
| 282 | if (iter == m.end()) { |
| 283 | return name; |
| 284 | } |
| 285 | name = base + '_'; |
| 286 | name += to_string(++anonCount); |
| 287 | } while (true); |
| 288 | // should never get here |
| 289 | return string(); |
| 290 | } |
| 291 | |
| 292 | void validate() const; |
| 293 | void writeCodeBlock(); |
| 294 | string writeCodeBlock(const Definition&, MarkType ); |
| 295 | string writeCodeBlock(TextParser& i, MarkType , int indent); |
| 296 | |
| 297 | void writeDefinition(const Definition& def) { |
| 298 | if (def.length() > 1) { |
| 299 | this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart); |
| 300 | this->lf(1); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | void writeDefinition(const Definition& def, string name, int spaces) { |
| 305 | this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart); |
| 306 | this->writeSpace(spaces); |
| 307 | this->writeString(name); |
| 308 | this->lf(1); |
| 309 | } |
| 310 | |
| 311 | void writeEndTag() { |
| 312 | this->lf(1); |
| 313 | this->writeString("##"); |
| 314 | this->lf(1); |
| 315 | } |
| 316 | |
| 317 | void writeEndTag(const char* tagType) { |
| 318 | this->lf(1); |
| 319 | this->writeString(string("#") + tagType + " ##"); |
| 320 | this->lf(1); |
| 321 | } |
| 322 | |
| 323 | void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) { |
| 324 | this->lf(1); |
| 325 | this->writeString(string("#") + tagType + " " + tagID); |
| 326 | this->writeSpace(spaces); |
| 327 | this->writeString("##"); |
| 328 | this->lf(1); |
| 329 | } |
| 330 | |
| 331 | void writeEndTag(const char* tagType, string tagID, int spaces = 1) { |
| 332 | this->writeEndTag(tagType, tagID.c_str(), spaces); |
| 333 | } |
| 334 | |
| 335 | void writeIncompleteTag(const char* tagType, string tagID, int spaces = 1) { |
| 336 | this->writeString(string("#") + tagType + " " + tagID); |
| 337 | this->writeSpace(spaces); |
| 338 | this->writeString("incomplete"); |
| 339 | this->writeSpace(); |
| 340 | this->writeString("##"); |
| 341 | this->lf(1); |
| 342 | } |
| 343 | |
| 344 | void writeIncompleteTag(const char* tagType) { |
| 345 | this->writeString(string("#") + tagType + " incomplete ##"); |
| 346 | this->lf(1); |
| 347 | } |
| 348 | |
| 349 | void writeTableHeader(const char* col1, size_t pad, const char* col2) { |
| 350 | this->lf(1); |
| 351 | this->writeString("#Table"); |
| 352 | this->lf(1); |
| 353 | this->writeString("#Legend"); |
| 354 | this->lf(1); |
| 355 | string legend = "# "; |
| 356 | legend += col1; |
| 357 | if (pad > strlen(col1)) { |
| 358 | legend += string(pad - strlen(col1), ' '); |
| 359 | } |
| 360 | legend += " # "; |
| 361 | legend += col2; |
| 362 | legend += " ##"; |
| 363 | this->writeString(legend); |
| 364 | this->lf(1); |
| 365 | this->writeString("#Legend ##"); |
| 366 | this->lf(1); |
| 367 | } |
| 368 | |
| 369 | void writeTableRow(size_t pad, string col1) { |
| 370 | this->lf(1); |
| 371 | string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##"; |
| 372 | this->writeString(row); |
| 373 | this->lf(1); |
| 374 | } |
| 375 | |
| 376 | void writeTableRow(size_t pad1, string col1, size_t pad2, string col2) { |
| 377 | this->lf(1); |
| 378 | string row = "# " + col1 + string(pad1 - col1.length(), ' ') + " # " + |
| 379 | col2 + string(pad2 - col2.length(), ' ') + " ##"; |
| 380 | this->writeString(row); |
| 381 | this->lf(1); |
| 382 | } |
| 383 | |
| 384 | void writeTableTrailer() { |
| 385 | this->lf(1); |
| 386 | this->writeString("#Table ##"); |
| 387 | this->lf(1); |
| 388 | } |
| 389 | |
| 390 | void writeTag(const char* tagType) { |
| 391 | this->lf(1); |
| 392 | this->writeString("#"); |
| 393 | this->writeString(tagType); |
| 394 | } |
| 395 | |
| 396 | void writeTagNoLF(const char* tagType, const char* tagID) { |
| 397 | this->writeString("#"); |
| 398 | this->writeString(tagType); |
| 399 | this->writeSpace(); |
| 400 | this->writeString(tagID); |
| 401 | } |
| 402 | |
| 403 | void writeTagNoLF(const char* tagType, string tagID) { |
| 404 | this->writeTagNoLF(tagType, tagID.c_str()); |
| 405 | } |
| 406 | |
| 407 | void writeTag(const char* tagType, const char* tagID) { |
| 408 | this->lf(1); |
| 409 | this->writeTagNoLF(tagType, tagID); |
| 410 | } |
| 411 | |
| 412 | void writeTag(const char* tagType, string tagID) { |
| 413 | this->writeTag(tagType, tagID.c_str()); |
| 414 | } |
| 415 | |
| 416 | void writeTagTable(string tagType, string body) { |
| 417 | this->writeTag(tagType.c_str()); |
| 418 | this->writeSpace(1); |
| 419 | this->writeString("#"); |
| 420 | this->writeSpace(1); |
| 421 | this->writeString(body); |
| 422 | this->writeSpace(1); |
| 423 | this->writeString("##"); |
| 424 | } |
| 425 | |
| 426 | protected: |
| 427 | static void ValidateKeyWords(); |
| 428 | |
| 429 | struct DefinitionMap { |
| 430 | unordered_map<string, Definition*>* fInclude; |
| 431 | MarkType fMarkType; |
| 432 | }; |
| 433 | |
| 434 | vector<DefinitionMap> fMaps; |
| 435 | unordered_map<string, Definition> fIncludeMap; |
| 436 | list<Definition> fGlobals; |
| 437 | unordered_map<string, IClassDefinition> fIClassMap; |
| 438 | unordered_map<string, Definition*> fIConstMap; |
| 439 | unordered_map<string, Definition*> fIDefineMap; |
| 440 | unordered_map<string, Definition*> fIEnumMap; |
| 441 | unordered_map<string, Definition*> fIFunctionMap; |
| 442 | unordered_map<string, Definition*> fIStructMap; |
| 443 | unordered_map<string, Definition*> fITemplateMap; |
| 444 | unordered_map<string, Definition*> fITypedefMap; |
| 445 | unordered_map<string, Definition*> fIUnionMap; |
| 446 | CheckCode fCheck; |
| 447 | Definition* fRootTopic; |
| 448 | Definition* fConstExpr; |
| 449 | Definition* fInBrace; |
| 450 | Definition* fLastObject; |
| 451 | Definition* fPriorEnum; |
| 452 | Definition* fPriorObject; |
| 453 | int fPriorIndex; |
| 454 | const char* fIncludeWord; |
| 455 | Elided fElided; |
| 456 | char fPrev; |
| 457 | bool fInChar; |
| 458 | bool fInCharCommentString; |
| 459 | bool fInComment; |
| 460 | bool fInDefine; |
| 461 | bool fInEnum; |
| 462 | bool fInFunction; |
| 463 | bool fInString; |
| 464 | bool fFailed; |
| 465 | |
| 466 | typedef ParserCommon INHERITED; |
| 467 | }; |
| 468 | |
| 469 | #endif |