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 mdOut_DEFINED 9 #define mdOut_DEFINED 10 11 #include "parserCommon.h" 12 13 class IncludeParser; 14 15 class MdOut : public ParserCommon { 16 public: 17 struct SubtopicDescriptions { 18 string fSingular; 19 string fPlural; 20 string fOneLiner; 21 string fDetails; 22 }; 23 24 MdOut(BmhParser& bmh, IncludeParser& inc) : ParserCommon() 25 , fBmhParser(bmh) 26 , fIncludeParser(inc) { 27 this->reset(); 28 this->addPopulators(); 29 fBmhParser.setUpGlobalSubstitutes(); 30 fNames = &fBmhParser.fGlobalNames; 31 } 32 33 bool buildReferences(const char* docDir, const char* mdOutDirOrFile); 34 bool buildStatus(const char* docDir, const char* mdOutDir); 35 void checkAnchors(); 36 37 private: 38 enum class TableState { 39 kNone, 40 kRow, 41 kColumn, 42 }; 43 44 struct AnchorDef { 45 string fDef; 46 MarkType fMarkType; 47 }; 48 49 struct DefinedState { 50 DefinedState(const MdOut& mdOut, const char* refStart, const char* refEnd, 51 Resolvable resolvable) 52 : fBmhParser(&mdOut.fBmhParser) 53 , fNames(mdOut.fNames) 54 , fGlobals(&mdOut.fBmhParser.fGlobalNames) 55 , fLastDef(mdOut.fLastDef) 56 , fMethod(mdOut.fMethod) 57 , fSubtopic(mdOut.fSubtopic) 58 , fRoot(mdOut.fRoot) 59 , fRefStart(refStart) 60 , fRefEnd(refEnd) 61 , fResolvable(resolvable) 62 , fInProgress(mdOut.fInProgress) { 63 TextParser matrixParser(fLastDef->fFileName, refStart, refEnd, fLastDef->fLineCount); 64 const char* bracket = matrixParser.anyOf("|=\n"); 65 fInMatrix = bracket && ('|' == bracket[0] || '=' == bracket[0]); 66 } 67 68 void backup() { 69 fPriorWord = fBack2Word; 70 fPriorLink = ""; 71 fPriorSeparator = ""; 72 fSeparator = fBack2Separator; 73 } 74 75 bool findEnd(const char* start) { 76 if (fEnd < fRefEnd && '~' == fEnd[0]) { 77 ++fEnd; 78 } 79 do { 80 while (fEnd < fRefEnd && (isalnum(fEnd[0]) || '-' == fEnd[0] || '_' == fEnd[0])) { 81 ++fEnd; 82 } 83 if (fEnd + 1 >= fRefEnd || '/' != fEnd[0] || start == fEnd || !isalpha(fEnd[-1]) 84 || !isalpha(fEnd[1])) { 85 break; // stop unless pattern is xxx/xxx as in I/O 86 } 87 ++fEnd; // skip slash 88 } while (true); 89 while (start != fEnd && '-' == fEnd[-1]) { 90 --fEnd; 91 } 92 return start == fEnd; 93 } 94 95 bool findLink(string ref, string* linkPtr, bool addParens); 96 bool findLink(string ref, string* linkPtr, unordered_map<string, Definition*>& map); 97 bool hasWordSpace(string wordSpace) const; 98 void setLink(); 99 100 string nextSeparator(const char* start) { 101 fBack2Separator = fPriorSeparator; 102 fPriorSeparator = fSeparator; 103 fEnd = start; 104 return fBack2Separator; 105 } 106 107 const char* nextWord() { 108 fBack2Word = fPriorWord; 109 fPriorWord = fWord; 110 fPriorLink = fLink; 111 return fEnd; 112 } 113 114 bool phraseContinues(string phrase, string* priorWord, string* priorLink) const; 115 116 void setLower() { 117 fAddParens = false; 118 bool allLower = std::all_of(fWord.begin(), fWord.end(), [](char c) { 119 return islower(c); 120 }); 121 bool hasParens = fEnd + 2 <= fRefEnd && "()" == string(fEnd, 2); 122 if (hasParens) { 123 if (allLower) { 124 fWord += "()"; 125 fEnd += 2; 126 } 127 } else if (allLower) { 128 fAddParens = true; 129 } 130 } 131 132 bool setPriorSpaceWord(const char** startPtr) { 133 if (!fPriorSpace) { 134 return false; 135 } 136 string phrase = fPriorWord + fWord; 137 if (this->phraseContinues(phrase, &fPriorWord, &fPriorLink)) { 138 *startPtr = fEnd; 139 return true; 140 } 141 fPriorWord = fPriorWord.substr(0, fPriorWord.length() - 1); 142 return false; 143 } 144 145 void skipParens() { 146 if ("()" == fSeparator.substr(0, 2)) { 147 string funcRef = fPriorWord + "()"; 148 if (this->findLink(funcRef, &fPriorLink, false)) { 149 fPriorWord = funcRef; 150 fSeparator = fSeparator.substr(2); 151 } 152 } 153 } 154 155 const char* skipWhiteSpace() { 156 const char* start = fSeparatorStart; 157 bool whiteSpace = start < fRefEnd && ' ' >= start[0]; 158 while (start < fRefEnd && !isalpha(start[0]) && '~' != start[0]) { 159 whiteSpace &= ' ' >= start[0]; 160 ++start; 161 } 162 fPriorSpace = false; 163 fSeparator = string(fSeparatorStart, start - fSeparatorStart); 164 if ("" != fPriorWord && whiteSpace) { 165 string wordSpace = fPriorWord + ' '; 166 if (this->hasWordSpace(wordSpace)) { 167 fPriorWord = wordSpace; 168 fPriorSpace = true; 169 } 170 } 171 return start; 172 } 173 174 string fRef; 175 string fBack2Word; 176 string fBack2Separator; 177 string fPriorWord; 178 string fPriorLink; 179 string fPriorSeparator; 180 string fWord; 181 string fLink; 182 string fSeparator; 183 string fMethodName; 184 BmhParser* fBmhParser; 185 const NameMap* fNames; 186 const NameMap* fGlobals; 187 const Definition* fLastDef; 188 const Definition* fMethod; 189 const Definition* fSubtopic; 190 const Definition* fPriorDef; 191 const RootDefinition* fRoot; 192 const char* fSeparatorStart; 193 const char* fRefStart; 194 const char* fRefEnd; 195 const char* fEnd; 196 Resolvable fResolvable; 197 bool fAddParens; 198 bool fInMatrix; 199 bool fInProgress; 200 bool fPriorSpace; 201 }; 202 203 void addCodeBlock(const Definition* def, string& str) const; 204 void addPopulators(); 205 string addReferences(const char* start, const char* end, Resolvable ); 206 string anchorDef(string def, string name); 207 string anchorLocalRef(string ref, string name); 208 string anchorRef(string def, string name); 209 bool buildRefFromFile(const char* fileName, const char* outDir); 210 bool checkParamReturnBody(const Definition* def); 211 Definition* checkParentsForMatch(Definition* test, string ref) const; 212 void childrenOut(Definition* def, const char* contentStart); 213 Definition* csParent(); 214 const Definition* findParamType(); 215 string getMemberTypeName(const Definition* def, string* memberType); 216 static bool HasDetails(const Definition* def); 217 void htmlOut(string ); 218 bool isDefined(DefinedState& s); 219 const Definition* isDefined(const TextParser& , Resolvable ); 220 string linkName(const Definition* ) const; 221 void markTypeOut(Definition* , const Definition** prior); 222 void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); } 223 void mdHeaderOutLF(int depth, int lf); 224 void parameterHeaderOut(TextParser& paramParser, const Definition** prior, Definition* def); 225 void parameterTrailerOut(); 226 bool parseFromFile(const char* path) override { return true; } 227 void populateOne(Definition* def, 228 unordered_map<string, RootDefinition::SubtopicContents>& populator); 229 void populateTables(const Definition* def, RootDefinition* ); 230 231 SubtopicDescriptions& populator(string key) { 232 auto entry = fPopulators.find(key); 233 // FIXME: this should have been detected earlier 234 SkASSERT(fPopulators.end() != entry); 235 return entry->second; 236 } 237 238 void reset() override { 239 INHERITED::resetCommon(); 240 fNames = nullptr; 241 fEnumClass = nullptr; 242 fMethod = nullptr; 243 fRoot = nullptr; 244 fSubtopic = nullptr; 245 fLastParam = nullptr; 246 fTableState = TableState::kNone; 247 fAddRefFailed = false; 248 fHasFiddle = false; 249 fInDescription = false; 250 fInList = false; 251 fResolveAndIndent = false; 252 fLiteralAndIndent = false; 253 fLastDef = nullptr; 254 fParamEnd = nullptr; 255 fInProgress = false; 256 } 257 258 Resolvable resolvable(const Definition* definition) const { 259 MarkType markType = definition->fMarkType; 260 if (MarkType::kCode == markType) { 261 for (auto child : definition->fChildren) { 262 if (MarkType::kLiteral == child->fMarkType) { 263 return Resolvable::kLiteral; 264 } 265 } 266 } 267 if ((MarkType::kExample == markType 268 || MarkType::kFunction == markType) && fHasFiddle) { 269 return Resolvable::kNo; 270 } 271 return BmhParser::kMarkProps[(int) markType].fResolve; 272 } 273 274 void resolveOut(const char* start, const char* end, Resolvable ); 275 void returnHeaderOut(const Definition** prior, Definition* def); 276 void rowOut(string col1, const Definition* col2); 277 void rowOut(const char * name, string description, bool literalName); 278 279 void subtopicOut(string name); 280 void subtopicsOut(Definition* def); 281 void subtopicOut(string key, const vector<Definition*>& data, const Definition* csParent, 282 const Definition* topicParent, bool showClones); 283 bool subtopicRowOut(string keyName, const Definition* entry); 284 void summaryOut(const Definition* def, MarkType , string name); 285 string tableDataCodeDef(const Definition* def); 286 string tableDataCodeDef(string def, string name); 287 string tableDataCodeLocalRef(string name); 288 string tableDataCodeLocalRef(string ref, string name); 289 string tableDataCodeRef(const Definition* ref); 290 string tableDataCodeRef(string ref, string name); 291 void writeSubtopicTableHeader(string key); 292 293 vector<const Definition*> fClassStack; 294 unordered_map<string, vector<AnchorDef> > fAllAnchorDefs; 295 unordered_map<string, vector<string> > fAllAnchorRefs; 296 NameMap* fNames; 297 BmhParser& fBmhParser; 298 IncludeParser& fIncludeParser; 299 const Definition* fEnumClass; 300 const Definition* fLastDef; 301 Definition* fMethod; 302 RootDefinition* fRoot; // used in generating populated tables; always struct or class 303 RootDefinition* fSubtopic; // used in resolving symbols 304 const Definition* fLastParam; 305 TableState fTableState; 306 unordered_map<string, SubtopicDescriptions> fPopulators; 307 unordered_map<string, string> fPhraseParams; 308 const char* fParamEnd; 309 bool fAddRefFailed; 310 bool fHasFiddle; 311 bool fInDescription; // FIXME: for now, ignore unfound camelCase in description since it may 312 // be defined in example which at present cannot be linked to 313 bool fInList; 314 bool fLiteralAndIndent; 315 bool fResolveAndIndent; 316 bool fOddRow; 317 bool fHasDetails; 318 bool fInProgress; 319 typedef ParserCommon INHERITED; 320 }; 321 322 #endif 323