• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 bookmaker_DEFINED
9 #define bookmaker_DEFINED
10 
11 #include "SkCommandLineFlags.h"
12 #include "SkData.h"
13 #include "SkJSONCPP.h"
14 
15 #include <algorithm>
16 #include <cmath>
17 #include <cctype>
18 #include <forward_list>
19 #include <list>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23 
24 // std::to_string isn't implemented on android
25 #include <sstream>
26 
27 template <typename T>
to_string(T value)28 std::string to_string(T value)
29 {
30     std::ostringstream os ;
31     os << value ;
32     return os.str() ;
33 }
34 
35 using std::forward_list;
36 using std::list;
37 using std::unordered_map;
38 using std::string;
39 using std::vector;
40 
41 enum class KeyWord {
42     kNone,
43     kSK_API,
44     kSK_BEGIN_REQUIRE_DENSE,
45     kBool,
46     kChar,
47     kClass,
48     kConst,
49     kConstExpr,
50     kDefine,
51     kDouble,
52     kElif,
53     kElse,
54     kEndif,
55     kEnum,
56     kError,
57     kFloat,
58     kFriend,
59     kIf,
60     kIfdef,
61     kIfndef,
62     kInclude,
63     kInline,
64     kInt,
65     kOperator,
66     kPrivate,
67     kProtected,
68     kPublic,
69     kSigned,
70     kSize_t,
71     kStatic,
72     kStruct,
73     kTemplate,
74     kTypedef,
75     kUint16_t,
76     kUint32_t,
77     kUint64_t,
78     kUint8_t,
79     kUnion,
80     kUnsigned,
81     kVoid,
82 };
83 
84 enum class MarkType {
85     kNone,
86     kAnchor,
87     kAlias,
88     kBug,
89     kClass,
90     kCode,
91     kColumn,
92     kComment,
93     kConst,
94     kDefine,
95     kDefinedBy,
96     kDeprecated,
97     kDescription,
98     kDoxygen,
99     kDuration,
100     kEnum,
101     kEnumClass,
102     kExample,
103     kExperimental,
104     kExternal,
105     kFile,
106     kFormula,
107     kFunction,
108     kHeight,
109     kImage,
110 	kIn,
111     kLegend,
112 	kLine,
113     kLink,
114     kList,
115     kLiteral,  // don't lookup hyperlinks, do substitution, etc
116     kMarkChar,
117     kMember,
118     kMethod,
119     kNoExample,
120     kOutdent,
121     kParam,
122     kPlatform,
123     kPopulate,
124     kPrivate,
125     kReturn,
126     kRoot,
127     kRow,
128     kSeeAlso,
129     kSet,
130     kStdOut,
131     kStruct,
132     kSubstitute,
133     kSubtopic,
134     kTable,
135     kTemplate,
136     kText,
137     kTime,
138     kToDo,
139     kTopic,
140     kTrack,
141     kTypedef,
142     kUnion,
143     kVolatile,
144     kWidth,
145 };
146 
147 enum {
148     Last_MarkType = (int) MarkType::kWidth,
149 };
150 
151 enum class Bracket {
152     kNone,
153     kParen,
154     kSquare,
155     kBrace,
156     kAngle,
157     kString,
158     kChar,
159     kSlashStar,
160     kSlashSlash,
161     kPound,
162     kColon,
163     kDebugCode,  // parens get special treatment so SkDEBUGCODE( isn't treated as method
164 };
165 
166 enum class Punctuation {  // catch-all for misc symbols tracked in C
167     kNone,
168     kAsterisk,  // for pointer-to
169     kSemicolon,  // e.g., to delinate xxx() const ; const int* yyy()
170     kLeftBrace,
171     kColon,     // for foo() : bar(1), baz(2) {}
172 };
173 
174 enum class KeyProperty {
175     kNone,
176     kClassSection,
177     kFunction,
178     kModifier,
179     kNumber,
180     kObject,
181     kPreprocessor,
182 };
183 
184 enum class StatusFilter {
185     kCompleted,
186     kInProgress,
187     kUnknown,
188 };
189 
190 struct IncludeKey {
191     const char* fName;
192     KeyWord fKeyWord;
193     KeyProperty fProperty;
194 };
195 
196 extern const IncludeKey kKeyWords[];
197 
has_nonwhitespace(const string & s)198 static inline bool has_nonwhitespace(const string& s) {
199     bool nonwhite = false;
200     for (const char& c : s) {
201         if (' ' < c) {
202             nonwhite = true;
203             break;
204         }
205     }
206     return nonwhite;
207 }
208 
trim_end(string & s)209 static inline void trim_end(string &s) {
210     s.erase(std::find_if(s.rbegin(), s.rend(),
211             std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
212 }
213 
trim_end_spaces(string & s)214 static inline void trim_end_spaces(string &s) {
215     while (s.length() > 0 && ' ' == s.back()) {
216         s.pop_back();
217     }
218 }
219 
trim_start(string & s)220 static inline void trim_start(string &s) {
221     s.erase(s.begin(), std::find_if(s.begin(), s.end(),
222             std::not1(std::ptr_fun<int, int>(std::isspace))));
223 }
224 
trim_start_end(string & s)225 static inline void trim_start_end(string& s) {
226     trim_start(s);
227     trim_end(s);
228 }
229 
230 class NonAssignable {
231 public:
232     NonAssignable(NonAssignable const&) = delete;
233     NonAssignable& operator=(NonAssignable const&) = delete;
NonAssignable()234     NonAssignable() {}
235 };
236 
237 class Definition;
238 
239 class TextParser : public NonAssignable {
TextParser()240     TextParser() {}  // only for ParserCommon to call
241     friend class ParserCommon;
242 public:
~TextParser()243     virtual ~TextParser() {}
244     class Save {
245     public:
Save(TextParser * parser)246         Save(TextParser* parser) {
247             fParser = parser;
248             fLine = parser->fLine;
249             fChar = parser->fChar;
250             fLineCount = parser->fLineCount;
251         }
252 
restore()253         void restore() const {
254             fParser->fLine = fLine;
255             fParser->fChar = fChar;
256             fParser->fLineCount = fLineCount;
257         }
258 
259     private:
260         TextParser* fParser;
261         const char* fLine;
262         const char* fChar;
263         int fLineCount;
264     };
265 
TextParser(const string & fileName,const char * start,const char * end,int lineCount)266     TextParser(const string& fileName, const char* start, const char* end, int lineCount)
267         : fFileName(fileName)
268         , fStart(start)
269         , fLine(start)
270         , fChar(start)
271         , fEnd(end)
272         , fLineCount(lineCount)
273     {
274     }
275 
276     TextParser(const Definition* );
277 
anyOf(const char * str)278     const char* anyOf(const char* str) const {
279         const char* ptr = fChar;
280         while (ptr < fEnd) {
281             if (strchr(str, ptr[0])) {
282                 return ptr;
283             }
284             ++ptr;
285         }
286         return nullptr;
287     }
288 
anyOf(const char * wordStart,const char * wordList[],size_t wordListCount)289     const char* anyOf(const char* wordStart, const char* wordList[], size_t wordListCount) const {
290         const char** wordPtr = wordList;
291         const char** wordEnd = wordPtr + wordListCount;
292         const size_t matchLen = fChar - wordStart;
293         while (wordPtr < wordEnd) {
294             const char* word = *wordPtr++;
295             if (strlen(word) == matchLen && !strncmp(wordStart, word, matchLen)) {
296                 return word;
297             }
298         }
299         return nullptr;
300     }
301 
backup(const char * pattern)302     char backup(const char* pattern) const {
303         size_t len = strlen(pattern);
304         const char* start = fChar - len;
305         if (start <= fStart) {
306             return '\0';
307         }
308         if (strncmp(start, pattern, len)) {
309             return '\0';
310         }
311         return start[-1];
312     }
313 
contains(const char * match,const char * lineEnd,const char ** loc)314     bool contains(const char* match, const char* lineEnd, const char** loc) const {
315         *loc = this->strnstr(match, lineEnd);
316         return *loc;
317     }
318 
doubleLF()319     const char* doubleLF() const {
320         int count = 0;
321         const char* ptr = fChar;
322         const char* doubleStart = nullptr;
323         while (ptr < fEnd) {
324             if ('\n' == ptr[0]) {
325                 if (++count == 1) {
326                     doubleStart = ptr;
327                 } else {
328                     return doubleStart;
329                 }
330             } else if (' ' < ptr[0]) {
331                 count = 0;
332             }
333             ++ptr;
334         }
335         return nullptr;
336     }
337 
endsWith(const char * match)338     bool endsWith(const char* match) {
339         int matchLen = strlen(match);
340         if (matchLen > fChar - fLine) {
341             return false;
342         }
343         return !strncmp(fChar - matchLen, match, matchLen);
344     }
345 
eof()346     bool eof() const { return fChar >= fEnd; }
347 
lineEnd()348     const char* lineEnd() const {
349         const char* ptr = fChar;
350         do {
351             if (ptr >= fEnd) {
352                 return ptr;
353             }
354             char test = *ptr++;
355             if (test == '\n' || test == '\0') {
356                 break;
357             }
358         } while (true);
359         return ptr;
360     }
361 
lineLength()362     ptrdiff_t lineLength() const {
363         return this->lineEnd() - fLine;
364     }
365 
366     bool match(TextParser* );
367 
next()368     char next() {
369         SkASSERT(fChar < fEnd);
370         char result = *fChar++;
371         if ('\n' == result) {
372             ++fLineCount;
373             fLine = fChar;
374         }
375         return result;
376     }
377 
peek()378     char peek() const { SkASSERT(fChar < fEnd); return *fChar; }
379 
restorePlace(const TextParser & save)380     void restorePlace(const TextParser& save) {
381         fChar = save.fChar;
382         fLine = save.fLine;
383         fLineCount = save.fLineCount;
384     }
385 
savePlace(TextParser * save)386     void savePlace(TextParser* save) {
387         save->fChar = fChar;
388         save->fLine = fLine;
389         save->fLineCount = fLineCount;
390     }
391 
392     void reportError(const char* errorStr) const;
393     void reportWarning(const char* errorStr) const;
394 
reportError(const char * errorStr)395     template <typename T> T reportError(const char* errorStr) const {
396         this->reportError(errorStr);
397         return T();
398     }
399 
sentenceEnd(const char * check)400     bool sentenceEnd(const char* check) const {
401         while (check > fStart) {
402             --check;
403             if (' ' < check[0] && '.' != check[0]) {
404                 return false;
405             }
406             if ('.' == check[0]) {
407                 return ' ' >= check[1];
408             }
409             if ('\n' == check[0] && '\n' == check[1]) {
410                 return true;
411             }
412         }
413         return true;
414     }
415 
416     bool skipToEndBracket(char endBracket, const char* end = nullptr) {
417         if (nullptr == end) {
418             end = fEnd;
419         }
420         while (fChar[0] != endBracket) {
421             if (fChar >= end) {
422                 return false;
423             }
424             (void) this->next();
425         }
426         return true;
427     }
428 
skipToEndBracket(const char * endBracket)429     bool skipToEndBracket(const char* endBracket) {
430         size_t len = strlen(endBracket);
431         while (strncmp(fChar, endBracket, len)) {
432             if (fChar >= fEnd) {
433                 return false;
434             }
435             (void) this->next();
436         }
437         return true;
438     }
439 
skipLine()440     bool skipLine() {
441         return skipToEndBracket('\n');
442     }
443 
skipTo(const char * skip)444     void skipTo(const char* skip) {
445        while (fChar < skip) {
446            this->next();
447        }
448     }
449 
skipToAlpha()450     void skipToAlpha() {
451         while (fChar < fEnd && !isalpha(fChar[0])) {
452             fChar++;
453         }
454     }
455 
skipToAlphaNum()456     void skipToAlphaNum() {
457         while (fChar < fEnd && !isalnum(fChar[0])) {
458             fChar++;
459         }
460     }
461 
skipExact(const char * pattern)462     bool skipExact(const char* pattern) {
463         if (!this->startsWith(pattern)) {
464             return false;
465         }
466         this->skipName(pattern);
467         return true;
468     }
469 
470     // differs from skipToNonAlphaNum in that a.b isn't considered a full name,
471     // since a.b can't be found as a named definition
skipFullName()472     void skipFullName() {
473         while (fChar < fEnd && (isalnum(fChar[0])
474                 || '_' == fChar[0]  /* || '-' == fChar[0] */
475                 || (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]))) {
476             if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
477                 fChar++;
478             }
479             fChar++;
480         }
481     }
482 
skipToLineStart()483     bool skipToLineStart() {
484         if (!this->skipLine()) {
485             return false;
486         }
487         if (!this->eof()) {
488             return this->skipWhiteSpace();
489         }
490         return true;
491     }
492 
skipToNonAlphaNum()493     void skipToNonAlphaNum() {
494         while (fChar < fEnd && (isalnum(fChar[0])
495                 || '_' == fChar[0] || '-' == fChar[0]
496                 || (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
497                 || ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
498             if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
499                 fChar++;
500             }
501             fChar++;
502         }
503     }
504 
skipToSpace()505     void skipToSpace() {
506         while (fChar < fEnd && ' ' != fChar[0]) {
507             fChar++;
508         }
509     }
510 
skipToWhiteSpace()511     void skipToWhiteSpace() {
512         while (fChar < fEnd && ' ' < fChar[0]) {
513             fChar++;
514         }
515     }
516 
skipName(const char * word)517     bool skipName(const char* word) {
518         size_t len = strlen(word);
519         if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
520             for (size_t i = 0; i < len; ++i) {
521                 this->next();
522             }
523         }
524         return this->eof() || ' ' >= fChar[0];
525     }
526 
skipSpace()527     bool skipSpace() {
528         while (' ' == this->peek()) {
529             (void) this->next();
530             if (fChar >= fEnd) {
531                 return false;
532             }
533         }
534         return true;
535     }
536 
skipWord(const char * word)537     bool skipWord(const char* word) {
538         if (!this->skipWhiteSpace()) {
539             return false;
540         }
541         const char* save = fChar;
542         if (!this->skipName(word)) {
543             fChar = save;
544             return false;
545         }
546         if (!this->skipWhiteSpace()) {
547             return false;
548         }
549         return true;
550     }
551 
skipWhiteSpace()552     bool skipWhiteSpace() {
553         while (' ' >= this->peek()) {
554             (void) this->next();
555             if (fChar >= fEnd) {
556                 return false;
557             }
558         }
559         return true;
560     }
561 
startsWith(const char * str)562     bool startsWith(const char* str) const {
563         size_t len = strlen(str);
564         ptrdiff_t lineLen = fEnd - fChar;
565         return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
566     }
567 
568     // ignores minor white space differences
startsWith(const char * str,size_t oLen)569     bool startsWith(const char* str, size_t oLen) const {
570         size_t tIndex = 0;
571         size_t tLen = fEnd - fChar;
572         size_t oIndex = 0;
573         while (oIndex < oLen && tIndex < tLen) {
574             bool tSpace = ' ' >= fChar[tIndex];
575             bool oSpace = ' ' >= str[oIndex];
576             if (tSpace != oSpace) {
577                 break;
578             }
579             if (tSpace) {
580                 do {
581                     ++tIndex;
582                 } while (tIndex < tLen && ' ' >= fChar[tIndex]);
583                 do {
584                     ++oIndex;
585                 } while (oIndex < oLen && ' ' >= str[oIndex]);
586                 continue;
587             }
588             if (fChar[tIndex] != str[oIndex]) {
589                 break;
590             }
591             ++tIndex;
592             ++oIndex;
593         }
594         return oIndex >= oLen;
595     }
596 
strnchr(char ch,const char * end)597     const char* strnchr(char ch, const char* end) const {
598         const char* ptr = fChar;
599         while (ptr < end) {
600             if (ptr[0] == ch) {
601                 return ptr;
602             }
603             ++ptr;
604         }
605         return nullptr;
606     }
607 
strnstr(const char * match,const char * end)608     const char* strnstr(const char *match, const char* end) const {
609         size_t matchLen = strlen(match);
610         SkASSERT(matchLen > 0);
611         ptrdiff_t len = end - fChar;
612         SkASSERT(len >= 0);
613         if ((size_t) len < matchLen ) {
614             return nullptr;
615         }
616         size_t count = len - matchLen;
617         for (size_t index = 0; index <= count; index++) {
618             if (0 == strncmp(&fChar[index], match, matchLen)) {
619                 return &fChar[index];
620             }
621         }
622         return nullptr;
623     }
624 
trimmedBracketEnd(const char bracket)625     const char* trimmedBracketEnd(const char bracket) const {
626         int max = (int) (this->lineLength());
627         int index = 0;
628         while (index < max && bracket != fChar[index]) {
629             ++index;
630         }
631         SkASSERT(index < max);
632         while (index > 0 && ' ' >= fChar[index - 1]) {
633             --index;
634         }
635         return fChar + index;
636     }
637 
trimmedLineEnd()638     const char* trimmedLineEnd() const {
639         const char* result = this->lineEnd();
640         while (result > fChar && ' ' >= result[-1]) {
641             --result;
642         }
643         return result;
644     }
645 
trimEnd()646     void trimEnd() {
647         while (fEnd > fStart && ' ' >= fEnd[-1]) {
648             --fEnd;
649         }
650     }
651 
652     // FIXME: nothing else in TextParser knows from C++ --
653     // there could be a class between TextParser and ParserCommon
654     virtual string typedefName();
655 
wordEnd()656     const char* wordEnd() const {
657         const char* end = fChar;
658         while (isalnum(end[0]) || '_' == end[0] || '-' == end[0]) {
659             ++end;
660         }
661         return end;
662     }
663 
664     string fFileName;
665     const char* fStart;
666     const char* fLine;
667     const char* fChar;
668     const char* fEnd;
669     size_t fLineCount;
670 };
671 
672 class EscapeParser : public TextParser {
673 public:
EscapeParser(const char * start,const char * end)674     EscapeParser(const char* start, const char* end) :
675             TextParser("", start, end, 0) {
676         const char* reader = fStart;
677         fStorage = new char[end - start];
678         char* writer = fStorage;
679         while (reader < fEnd) {
680             char ch = *reader++;
681             if (ch != '\\') {
682                 *writer++ = ch;
683             } else {
684                 char ctrl = *reader++;
685                 if (ctrl == 'u') {
686                     unsigned unicode = 0;
687                     for (int i = 0; i < 4; ++i) {
688                         unicode <<= 4;
689                         SkASSERT((reader[0] >= '0' && reader[0] <= '9') ||
690                             (reader[0] >= 'A' && reader[0] <= 'F') ||
691                             (reader[0] >= 'a' && reader[0] <= 'f'));
692                         int nibble = *reader++ - '0';
693                         if (nibble > 9) {
694                             nibble = (nibble & ~('a' - 'A')) - 'A' + '9' + 1;
695                         }
696                         unicode |= nibble;
697                     }
698                     SkASSERT(unicode < 256);
699                     *writer++ = (unsigned char) unicode;
700                 } else {
701                     SkASSERT(ctrl == 'n');
702                     *writer++ = '\n';
703                 }
704             }
705         }
706         fStart = fLine = fChar = fStorage;
707         fEnd = writer;
708     }
709 
~EscapeParser()710     ~EscapeParser() override {
711         delete fStorage;
712     }
713 private:
714     char* fStorage;
715 };
716 
717 class RootDefinition;
718 
719 class Definition : public NonAssignable {
720 public:
721     enum Type {
722         kNone,
723         kWord,
724         kMark,
725         kKeyWord,
726         kBracket,
727         kPunctuation,
728         kFileType,
729     };
730 
731     enum class TrimExtract {
732         kNo,
733         kYes
734     };
735 
736     enum class ExampleOptions {
737         kText,
738         kPng,
739         kAll
740     };
741 
742     enum class MethodType {
743         kNone,
744         kConstructor,
745         kDestructor,
746         kOperator,
747     };
748 
749     enum class Operator {
750         kUnknown,
751         kAdd,
752         kAddTo,
753         kArray,
754         kCast,
755         kCopy,
756         kDelete,
757         kDereference,
758         kEqual,
759         kMinus,
760         kMove,
761         kMultiply,
762         kMultiplyBy,
763         kNew,
764         kNotEqual,
765         kSubtract,
766         kSubtractFrom,
767     };
768 
Definition()769     Definition() {}
770 
Definition(const char * start,const char * end,int line,Definition * parent)771     Definition(const char* start, const char* end, int line, Definition* parent)
772         : fStart(start)
773         , fContentStart(start)
774         , fContentEnd(end)
775         , fParent(parent)
776         , fLineCount(line)
777         , fType(Type::kWord) {
778         if (parent) {
779             SkASSERT(parent->fFileName.length() > 0);
780             fFileName = parent->fFileName;
781         }
782         this->setParentIndex();
783     }
784 
Definition(MarkType markType,const char * start,int line,Definition * parent)785     Definition(MarkType markType, const char* start, int line, Definition* parent)
786         : Definition(markType, start, nullptr, line, parent) {
787     }
788 
Definition(MarkType markType,const char * start,const char * end,int line,Definition * parent)789     Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent)
790         : Definition(start, end, line, parent) {
791         fMarkType = markType;
792         fType = Type::kMark;
793     }
794 
Definition(Bracket bracket,const char * start,int lineCount,Definition * parent)795     Definition(Bracket bracket, const char* start, int lineCount, Definition* parent)
796         : Definition(start, nullptr, lineCount, parent) {
797         fBracket = bracket;
798         fType = Type::kBracket;
799     }
800 
Definition(KeyWord keyWord,const char * start,const char * end,int lineCount,Definition * parent)801     Definition(KeyWord keyWord, const char* start, const char* end, int lineCount,
802             Definition* parent)
803         : Definition(start, end, lineCount, parent) {
804         fKeyWord = keyWord;
805         fType = Type::kKeyWord;
806     }
807 
Definition(Punctuation punctuation,const char * start,int lineCount,Definition * parent)808     Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent)
809         : Definition(start, nullptr, lineCount, parent) {
810         fPunctuation = punctuation;
811         fType = Type::kPunctuation;
812     }
813 
~Definition()814     virtual ~Definition() {}
815 
asRoot()816     virtual RootDefinition* asRoot() { SkASSERT(0); return nullptr; }
asRoot()817     virtual const RootDefinition* asRoot() const { SkASSERT(0); return nullptr; }
818     bool boilerplateIfDef(Definition* parent);
819     bool boilerplateDef(Definition* parent);
820 
boilerplateEndIf()821     bool boilerplateEndIf() {
822         return true;
823     }
824 
825     bool checkMethod() const;
826     bool crossCheck2(const Definition& includeToken) const;
827     bool crossCheck(const Definition& includeToken) const;
828     bool crossCheckInside(const char* start, const char* end, const Definition& includeToken) const;
829 
csParent()830     const Definition* csParent() const {
831         Definition* test = fParent;
832         while (test) {
833             if (MarkType::kStruct == test->fMarkType || MarkType::kClass == test->fMarkType) {
834                 return test;
835             }
836             test = test->fParent;
837         }
838         return nullptr;
839     }
840 
841     bool exampleToScript(string* result, ExampleOptions ) const;
842     string extractText(TrimExtract trimExtract) const;
843     string fiddleName() const;
844     string formatFunction() const;
845     const Definition* hasChild(MarkType markType) const;
846     bool hasMatch(const string& name) const;
847     const Definition* hasParam(const string& ref) const;
isClone()848     bool isClone() const { return fClone; }
849 
iRootParent()850     Definition* iRootParent() {
851         Definition* test = fParent;
852         while (test) {
853             if (Type::kKeyWord == test->fType && KeyWord::kClass == test->fKeyWord) {
854                 return test;
855             }
856             test = test->fParent;
857         }
858         return nullptr;
859     }
860 
isRoot()861     virtual bool isRoot() const { return false; }
862     bool isStructOrClass() const;
863 
length()864     int length() const {
865         return (int) (fContentEnd - fContentStart);
866     }
867 
868     bool methodHasReturn(const string& name, TextParser* methodParser) const;
869     string methodName() const;
870     bool nextMethodParam(TextParser* methodParser, const char** nextEndPtr,
871                          string* paramName) const;
872     static string NormalizedName(string name);
873     bool paramsMatch(const string& fullRef, const string& name) const;
874     bool parseOperator(size_t doubleColons, string& result);
875 
printableName()876     string printableName() const {
877         string result(fName);
878         std::replace(result.begin(), result.end(), '_', ' ');
879         return result;
880     }
881 
reportError(const char * errorStr)882     template <typename T> T reportError(const char* errorStr) const {
883         TextParser tp(this);
884         tp.reportError(errorStr);
885         return T();
886     }
887 
rootParent()888     virtual RootDefinition* rootParent() { SkASSERT(0); return nullptr; }
rootParent()889     virtual const RootDefinition* rootParent() const { SkASSERT(0); return nullptr; }
890     void setCanonicalFiddle();
891 
setParentIndex()892     void setParentIndex() {
893         fParentIndex = fParent ? (int) fParent->fTokens.size() : -1;
894     }
895 
896     void setWrapper();
897 
898     string fText;  // if text is constructed instead of in a file, it's put here
899     const char* fStart = nullptr;  // .. in original text file, or the start of fText
900     const char* fContentStart;  // start past optional markup name
901     string fName;
902     string fFiddle;  // if its a constructor or operator, fiddle name goes here
903     const char* fContentEnd = nullptr;  // the end of the contained text
904     const char* fTerminator = nullptr;  // the end of the markup, normally ##\n or \n
905     Definition* fParent = nullptr;
906     list<Definition> fTokens;
907     vector<Definition*> fChildren;
908     string fHash;  // generated by fiddle
909     string fFileName;
910     mutable string fWrapper; // used by Example to wrap into proper function
911     size_t fLineCount = 0;
912     int fParentIndex = 0;
913     MarkType fMarkType = MarkType::kNone;
914     KeyWord fKeyWord = KeyWord::kNone;
915     Bracket fBracket = Bracket::kNone;
916     Punctuation fPunctuation = Punctuation::kNone;
917     MethodType fMethodType = MethodType::kNone;
918     Operator fOperator = Operator::kUnknown;
919     Type fType = Type::kNone;
920     bool fClone = false;
921     bool fCloned = false;
922     bool fOperatorConst = false;
923     bool fPrivate = false;
924     bool fShort = false;
925     bool fMemberStart = false;
926     bool fAnonymous = false;
927     mutable bool fVisited = false;
928 };
929 
930 class RootDefinition : public Definition {
931 public:
932     enum class AllowParens {
933         kNo,
934         kYes,
935     };
936 
RootDefinition()937     RootDefinition() {
938     }
939 
RootDefinition(MarkType markType,const char * start,int line,Definition * parent)940     RootDefinition(MarkType markType, const char* start, int line, Definition* parent)
941             : Definition(markType, start, line, parent) {
942     }
943 
RootDefinition(MarkType markType,const char * start,const char * end,int line,Definition * parent)944     RootDefinition(MarkType markType, const char* start, const char* end, int line,
945             Definition* parent) : Definition(markType, start, end,  line, parent) {
946     }
947 
~RootDefinition()948     ~RootDefinition() override {
949         for (auto& iter : fBranches) {
950             delete iter.second;
951         }
952     }
953 
asRoot()954     RootDefinition* asRoot() override { return this; }
asRoot()955     const RootDefinition* asRoot() const override { return this; }
956     void clearVisited();
957     bool dumpUnVisited();
958     const Definition* find(const string& ref, AllowParens ) const;
isRoot()959     bool isRoot() const override { return true; }
rootParent()960     RootDefinition* rootParent() override { return fRootParent; }
rootParent()961     const RootDefinition* rootParent() const override { return fRootParent; }
setRootParent(RootDefinition * rootParent)962     void setRootParent(RootDefinition* rootParent) { fRootParent = rootParent; }
963 
964     unordered_map<string, RootDefinition*> fBranches;
965     unordered_map<string, Definition> fLeaves;
966 private:
967     RootDefinition* fRootParent = nullptr;
968 };
969 
970 struct IClassDefinition : public Definition {
971     unordered_map<string, Definition*> fEnums;
972     unordered_map<string, Definition*> fMembers;
973     unordered_map<string, Definition*> fMethods;
974     unordered_map<string, Definition*> fStructs;
975     unordered_map<string, Definition*> fTypedefs;
976 };
977 
978 struct Reference {
ReferenceReference979     Reference()
980         : fLocation(nullptr)
981         , fDefinition(nullptr) {
982     }
983 
984     const char* fLocation;  // .. in original text file
985     const Definition* fDefinition;
986 };
987 
988 struct TypeNames {
989     const char* fName;
990     MarkType fMarkType;
991 };
992 
993 class ParserCommon : public TextParser {
994 public:
995 
ParserCommon()996     ParserCommon() : TextParser()
997         , fParent(nullptr)
998         , fDebugOut(false)
999     {
1000     }
1001 
~ParserCommon()1002     ~ParserCommon() override {
1003     }
1004 
addDefinition(Definition * def)1005     void addDefinition(Definition* def) {
1006         fParent->fChildren.push_back(def);
1007         fParent = def;
1008     }
1009 
indentToColumn(int column)1010     void indentToColumn(int column) {
1011         SkASSERT(column >= fColumn);
1012         if (fDebugOut) {
1013             SkDebugf("%*s", column - fColumn, "");
1014         }
1015         fprintf(fOut, "%*s", column - fColumn, "");
1016         fColumn = column;
1017         fSpaces += column - fColumn;
1018     }
1019 
leadingPunctuation(const char * str,size_t len)1020     bool leadingPunctuation(const char* str, size_t len) const {
1021         if (!fPendingSpace) {
1022             return false;
1023         }
1024         if (len < 2) {
1025             return false;
1026         }
1027         if ('.' != str[0] && ',' != str[0] && ';' != str[0] && ':' != str[0]) {
1028             return false;
1029         }
1030         return ' ' >= str[1];
1031     }
1032 
lf(int count)1033     void lf(int count) {
1034         fPendingLF = SkTMax(fPendingLF, count);
1035         this->nl();
1036     }
1037 
lfAlways(int count)1038     void lfAlways(int count) {
1039         this->lf(count);
1040         this->writePending();
1041     }
1042 
lfcr()1043     void lfcr() {
1044         this->lf(1);
1045     }
1046 
nl()1047     void nl() {
1048         fLinefeeds = 0;
1049         fSpaces = 0;
1050         fColumn = 0;
1051         fPendingSpace = 0;
1052     }
1053 
1054     bool parseFile(const char* file, const char* suffix);
1055     bool parseStatus(const char* file, const char* suffix, StatusFilter filter);
1056     virtual bool parseFromFile(const char* path) = 0;
1057     bool parseSetup(const char* path);
1058 
popObject()1059     void popObject() {
1060         fParent->fContentEnd = fParent->fTerminator = fChar;
1061         fParent = fParent->fParent;
1062     }
1063 
1064     const char* ReadToBuffer(string filename, int* size);
1065 
1066     virtual void reset() = 0;
1067 
resetCommon()1068     void resetCommon() {
1069         fLine = fChar = fStart;
1070         fLineCount = 0;
1071         fParent = nullptr;
1072         fIndent = 0;
1073         fOut = nullptr;
1074         fMaxLF = 2;
1075         fPendingLF = 0;
1076         fPendingSpace = 0;
1077         fOutdentNext = false;
1078         nl();
1079    }
1080 
setAsParent(Definition * definition)1081     void setAsParent(Definition* definition) {
1082         if (fParent) {
1083             fParent->fChildren.push_back(definition);
1084             definition->fParent = fParent;
1085         }
1086         fParent = definition;
1087     }
1088 
singleLF()1089     void singleLF() {
1090         fMaxLF = 1;
1091     }
1092 
writeBlock(int size,const char * data)1093     void writeBlock(int size, const char* data) {
1094         SkAssertResult(writeBlockTrim(size, data));
1095     }
1096 
1097     void writeBlockIndent(int size, const char* data);
1098     bool writeBlockTrim(int size, const char* data);
1099 
writeCommentHeader()1100     void writeCommentHeader() {
1101         this->lf(2);
1102         this->writeString("/**");
1103         this->writeSpace();
1104     }
1105 
writeCommentTrailer()1106     void writeCommentTrailer() {
1107         this->writeString("*/");
1108         this->lfcr();
1109     }
1110 
1111     void writePending();
1112 
1113     // write a pending space, so that two consecutive calls
1114     // don't double write, and trailing spaces on lines aren't written
1115     void writeSpace(int count = 1) {
1116         SkASSERT(!fPendingLF);
1117         SkASSERT(!fLinefeeds);
1118         SkASSERT(fColumn > 0);
1119         SkASSERT(!fSpaces);
1120         fPendingSpace = count;
1121     }
1122 
1123     void writeString(const char* str);
1124 
writeString(const string & str)1125     void writeString(const string& str) {
1126         this->writeString(str.c_str());
1127     }
1128 
1129     bool writtenFileDiffers(string filename, string readname);
1130 
1131     unordered_map<string, sk_sp<SkData>> fRawData;
1132     unordered_map<string, vector<char>> fLFOnly;
1133     Definition* fParent;
1134     FILE* fOut;
1135     int fLinefeeds;    // number of linefeeds last written, zeroed on non-space
1136     int fMaxLF;        // number of linefeeds allowed
1137     int fPendingLF;    // number of linefeeds to write (can be suppressed)
1138     int fSpaces;       // number of spaces (indent) last written, zeroed on non-space
1139     int fColumn;       // current column; number of chars past last linefeed
1140     int fIndent;       // desired indention
1141     int fPendingSpace; // one or two spaces should preceed the next string or block
1142     char fLastChar;    // last written
1143     bool fDebugOut;    // set true to write to std out
1144     bool fOutdentNext; // set at end of embedded struct to prevent premature outdent
1145 private:
1146     typedef TextParser INHERITED;
1147 };
1148 
1149 struct JsonStatus {
1150     const Json::Value& fObject;
1151     Json::Value::iterator fIter;
1152     string fName;
1153 };
1154 
1155 class StatusIter : public ParserCommon {
1156 public:
1157     StatusIter(const char* statusFile, const char* suffix, StatusFilter);
~StatusIter()1158     ~StatusIter() override {}
1159     string baseDir();
empty()1160     bool empty() { return fStack.empty(); }
1161     bool next(string* file);
1162 protected:
1163     bool parseFromFile(const char* path) override;
1164     void reset() override;
1165 private:
1166     vector<JsonStatus> fStack;
1167     Json::Value fRoot;
1168     const char* fSuffix;
1169     StatusFilter fFilter;
1170 };
1171 
1172 class BmhParser : public ParserCommon {
1173 public:
1174     enum class MarkLookup {
1175         kRequire,
1176         kAllowUnknown,
1177     };
1178 
1179     enum class Resolvable {
1180         kNo,    // neither resolved nor output
1181         kYes,   // resolved, output
1182         kOut,   // not resolved, but output
1183         kLiteral, // output untouched (FIXME: is this really different from kOut?)
1184 		kClone, // resolved, output, with references to clones as well
1185     };
1186 
1187     enum class Exemplary {
1188         kNo,
1189         kYes,
1190         kOptional,
1191     };
1192 
1193     enum class TableState {
1194         kNone,
1195         kColumnStart,
1196         kColumnEnd,
1197     };
1198 
1199 #define M(mt) (1LL << (int) MarkType::k##mt)
1200 #define M_D M(Description)
1201 #define M_CS M(Class) | M(Struct)
1202 #define M_ST M(Subtopic) | M(Topic)
1203 #define M_CSST M_CS | M_ST
1204 #ifdef M_E
1205 #undef M_E
1206 #endif
1207 #define M_E M(Enum) | M(EnumClass)
1208 
1209 #define R_Y Resolvable::kYes
1210 #define R_N Resolvable::kNo
1211 #define R_O Resolvable::kOut
1212 #define R_C Resolvable::kClone
1213 
1214 #define E_Y Exemplary::kYes
1215 #define E_N Exemplary::kNo
1216 #define E_O Exemplary::kOptional
1217 
BmhParser(bool skip)1218     BmhParser(bool skip) : ParserCommon()
1219         , fMaps {
1220 // names without formal definitions (e.g. Column) aren't included
1221 // fill in other names once they're actually used
1222   { "",            nullptr,      MarkType::kNone,         R_Y, E_N, 0 }
1223 , { "A",           nullptr,      MarkType::kAnchor,       R_N, E_N, 0 }
1224 , { "Alias",       nullptr,      MarkType::kAlias,        R_N, E_N, 0 }
1225 , { "Bug",         nullptr,      MarkType::kBug,          R_N, E_N, 0 }
1226 , { "Class",       &fClassMap,   MarkType::kClass,        R_Y, E_O, M_CSST | M(Root) }
1227 , { "Code",        nullptr,      MarkType::kCode,         R_O, E_N, M_CSST | M_E | M(Method) }
1228 , { "",            nullptr,      MarkType::kColumn,       R_Y, E_N, M(Row) }
1229 , { "",            nullptr,      MarkType::kComment,      R_N, E_N, 0 }
1230 , { "Const",       &fConstMap,   MarkType::kConst,        R_Y, E_N, M_E | M_ST  }
1231 , { "Define",      nullptr,      MarkType::kDefine,       R_O, E_N, M_ST }
1232 , { "DefinedBy",   nullptr,      MarkType::kDefinedBy,    R_N, E_N, M(Method) }
1233 , { "Deprecated",  nullptr,      MarkType::kDeprecated,   R_Y, E_N, 0 }
1234 , { "Description", nullptr,      MarkType::kDescription,  R_Y, E_N, M(Example) | M(NoExample) }
1235 , { "Doxygen",     nullptr,      MarkType::kDoxygen,      R_Y, E_N, 0 }
1236 , { "Duration",    nullptr,      MarkType::kDuration,     R_N, E_N, M(Example) | M(NoExample) }
1237 , { "Enum",        &fEnumMap,    MarkType::kEnum,         R_Y, E_O, M_CSST | M(Root) }
1238 , { "EnumClass",   &fClassMap,   MarkType::kEnumClass,    R_Y, E_O, M_CSST | M(Root) }
1239 , { "Example",     nullptr,      MarkType::kExample,      R_O, E_N, M_CSST | M_E | M(Method) }
1240 , { "Experimental", nullptr,     MarkType::kExperimental, R_Y, E_N, 0 }
1241 , { "External",    nullptr,      MarkType::kExternal,     R_Y, E_N, M(Root) }
1242 , { "File",        nullptr,      MarkType::kFile,         R_N, E_N, M(Track) }
1243 , { "Formula",     nullptr,      MarkType::kFormula,      R_O, E_N,
1244                                                     M(Column) | M_ST | M(Member) | M(Method) | M_D }
1245 , { "Function",    nullptr,      MarkType::kFunction,     R_O, E_N, M(Example) | M(NoExample) }
1246 , { "Height",      nullptr,      MarkType::kHeight,       R_N, E_N, M(Example) | M(NoExample) }
1247 , { "Image",       nullptr,      MarkType::kImage,        R_N, E_N, M(Example) | M(NoExample) }
1248 , { "In",          nullptr,      MarkType::kIn,           R_N, E_N,
1249                                                              M_CSST | M_E | M(Method) | M(Typedef) }
1250 , { "Legend",      nullptr,      MarkType::kLegend,       R_Y, E_N, M(Table) }
1251 , { "Line",        nullptr,      MarkType::kLine,         R_N, E_N,
1252                                                              M_CSST | M_E | M(Method) | M(Typedef) }
1253 , { "",            nullptr,      MarkType::kLink,         R_N, E_N, M(Anchor) }
1254 , { "List",        nullptr,      MarkType::kList,         R_Y, E_N, M(Method) | M_CSST | M_E | M_D }
1255 , { "Literal",     nullptr,      MarkType::kLiteral,      R_N, E_N, M(Code) }
1256 , { "",            nullptr,      MarkType::kMarkChar,     R_N, E_N, 0 }
1257 , { "Member",      nullptr,      MarkType::kMember,       R_Y, E_N, M_CSST }
1258 , { "Method",      &fMethodMap,  MarkType::kMethod,       R_Y, E_Y, M_CSST }
1259 , { "NoExample",   nullptr,      MarkType::kNoExample,    R_O, E_N, M_CSST | M_E | M(Method) }
1260 , { "Outdent",     nullptr,      MarkType::kOutdent,      R_N, E_N, M(Code) }
1261 , { "Param",       nullptr,      MarkType::kParam,        R_Y, E_N, M(Method) }
1262 , { "Platform",    nullptr,      MarkType::kPlatform,     R_N, E_N, M(Example) | M(NoExample) }
1263 , { "Populate",    nullptr,      MarkType::kPopulate,     R_N, E_N, M(Subtopic) }
1264 , { "Private",     nullptr,      MarkType::kPrivate,      R_N, E_N, 0 }
1265 , { "Return",      nullptr,      MarkType::kReturn,       R_Y, E_N, M(Method) }
1266 , { "",            nullptr,      MarkType::kRoot,         R_Y, E_N, 0 }
1267 , { "",            nullptr,      MarkType::kRow,          R_Y, E_N, M(Table) | M(List) }
1268 , { "SeeAlso",     nullptr,      MarkType::kSeeAlso,      R_C, E_N,
1269                                                              M_CSST | M_E | M(Method) | M(Typedef) }
1270 , { "Set",         nullptr,      MarkType::kSet,          R_N, E_N, M(Example) | M(NoExample) }
1271 , { "StdOut",      nullptr,      MarkType::kStdOut,       R_N, E_N, M(Example) | M(NoExample) }
1272 , { "Struct",      &fClassMap,   MarkType::kStruct,       R_Y, E_O, M(Class) | M(Root) | M_ST }
1273 , { "Substitute",  nullptr,      MarkType::kSubstitute,   R_N, E_N, M_ST }
1274 , { "Subtopic",    nullptr,      MarkType::kSubtopic,     R_Y, E_Y, M_CSST }
1275 , { "Table",       nullptr,      MarkType::kTable,        R_Y, E_N, M(Method) | M_CSST | M_E }
1276 , { "Template",    nullptr,      MarkType::kTemplate,     R_Y, E_N, 0 }
1277 , { "",            nullptr,      MarkType::kText,         R_N, E_N, 0 }
1278 , { "Time",        nullptr,      MarkType::kTime,         R_Y, E_N, M(Track) }
1279 , { "ToDo",        nullptr,      MarkType::kToDo,         R_N, E_N, 0 }
1280 , { "Topic",       nullptr,      MarkType::kTopic,        R_Y, E_Y, M_CS | M(Root) | M(Topic) }
1281 , { "Track",       nullptr,      MarkType::kTrack,        R_Y, E_N, M_E | M_ST }
1282 , { "Typedef",     &fTypedefMap, MarkType::kTypedef,      R_Y, E_N, M(Class) | M_ST }
1283 , { "",            nullptr,      MarkType::kUnion,        R_Y, E_N, 0 }
1284 , { "Volatile",    nullptr,      MarkType::kVolatile,     R_N, E_N, M(StdOut) }
1285 , { "Width",       nullptr,      MarkType::kWidth,        R_N, E_N, M(Example) | M(NoExample) } }
1286 , fSkip(skip)
1287         {
1288             this->reset();
1289         }
1290 
1291 #undef R_O
1292 #undef R_N
1293 #undef R_Y
1294 
1295 #undef M_E
1296 #undef M_CSST
1297 #undef M_ST
1298 #undef M_CS
1299 #undef M_D
1300 #undef M
1301 
~BmhParser()1302     ~BmhParser() override {}
1303 
1304     bool addDefinition(const char* defStart, bool hasEnd, MarkType markType,
1305             const vector<string>& typeNameBuilder);
1306     bool checkExamples() const;
1307     bool checkParamReturn(const Definition* definition) const;
1308     bool dumpExamples(const char* fiddleJsonFileName) const;
1309     bool childOf(MarkType markType) const;
1310     string className(MarkType markType);
1311     bool collectExternals();
1312     int endHashCount() const;
1313     bool endTableColumn(const char* end, const char* terminator);
1314 
findBmhObject(MarkType markType,const string & typeName)1315     RootDefinition* findBmhObject(MarkType markType, const string& typeName) const {
1316         auto map = fMaps[(int) markType].fBmh;
1317         if (!map) {
1318             return nullptr;
1319         }
1320         return &(*map)[typeName];
1321     }
1322 
1323     bool findDefinitions();
1324     MarkType getMarkType(MarkLookup lookup) const;
1325     bool hasEndToken() const;
1326     string memberName();
1327     string methodName();
1328     const Definition* parentSpace() const;
1329 
parseFromFile(const char * path)1330     bool parseFromFile(const char* path) override {
1331         if (!INHERITED::parseSetup(path)) {
1332             return false;
1333         }
1334         fCheckMethods = !strstr(path, "undocumented.bmh");
1335         return findDefinitions();
1336     }
1337 
1338     bool popParentStack(Definition* definition);
1339     void reportDuplicates(const Definition& def, const string& dup) const;
1340 
reset()1341     void reset() override {
1342         INHERITED::resetCommon();
1343         fRoot = nullptr;
1344         fWorkingColumn = nullptr;
1345         fRow = nullptr;
1346         fTableState = TableState::kNone;
1347         fMC = '#';
1348         fInChar = false;
1349         fInCharCommentString = false;
1350         fInComment = false;
1351         fInEnum = false;
1352         fInString = false;
1353         fCheckMethods = false;
1354     }
1355 
1356     bool skipNoName();
1357     bool skipToDefinitionEnd(MarkType markType);
1358 	bool skipToString();
1359     void spellCheck(const char* match, SkCommandLineFlags::StringArray report) const;
1360     void spellStatus(const char* match, SkCommandLineFlags::StringArray report) const;
1361     vector<string> topicName();
1362     vector<string> typeName(MarkType markType, bool* expectEnd);
1363     string typedefName() override;
1364     string uniqueName(const string& base, MarkType markType);
1365     string uniqueRootName(const string& base, MarkType markType);
1366     void validate() const;
1367     string word(const string& prefix, const string& delimiter);
1368 
1369 public:
1370     struct DefinitionMap {
1371         const char* fName;
1372         unordered_map<string, RootDefinition>* fBmh;
1373         MarkType fMarkType;
1374         Resolvable fResolve;
1375         Exemplary fExemplary;  // worthy of an example
1376         uint64_t fParentMask;
1377     };
1378 
1379     DefinitionMap fMaps[Last_MarkType + 1];
1380     forward_list<RootDefinition> fTopics;
1381     forward_list<Definition> fMarkup;
1382     forward_list<RootDefinition> fExternals;
1383     vector<string> fInputFiles;
1384     unordered_map<string, RootDefinition> fClassMap;
1385     unordered_map<string, RootDefinition> fConstMap;
1386     unordered_map<string, RootDefinition> fEnumMap;
1387     unordered_map<string, RootDefinition> fMethodMap;
1388     unordered_map<string, RootDefinition> fTypedefMap;
1389     unordered_map<string, Definition*> fTopicMap;
1390     unordered_map<string, Definition*> fAliasMap;
1391     RootDefinition* fRoot;
1392     Definition* fWorkingColumn;
1393     Definition* fRow;
1394     const char* fColStart;
1395     TableState fTableState;
1396     mutable char fMC;  // markup character
1397     bool fAnonymous;
1398     bool fCloned;
1399     bool fInChar;
1400     bool fInCharCommentString;
1401     bool fInEnum;
1402     bool fInComment;
1403     bool fInString;
1404     bool fCheckMethods;
1405     bool fSkip = false;
1406     bool fWroteOut = false;
1407 private:
1408     typedef ParserCommon INHERITED;
1409 };
1410 
1411 class IncludeParser : public ParserCommon {
1412 public:
1413     enum class IsStruct {
1414         kNo,
1415         kYes,
1416     };
1417 
IncludeParser()1418     IncludeParser() : ParserCommon()
1419         , fMaps {
1420           { nullptr,        MarkType::kNone }
1421         , { nullptr,        MarkType::kAnchor }
1422         , { nullptr,        MarkType::kAlias }
1423         , { nullptr,        MarkType::kBug }
1424         , { nullptr,        MarkType::kClass }
1425         , { nullptr,        MarkType::kCode }
1426         , { nullptr,        MarkType::kColumn }
1427         , { nullptr,        MarkType::kComment }
1428         , { nullptr,        MarkType::kConst }
1429         , { &fIDefineMap,   MarkType::kDefine }
1430         , { nullptr,        MarkType::kDefinedBy }
1431         , { nullptr,        MarkType::kDeprecated }
1432         , { nullptr,        MarkType::kDescription }
1433         , { nullptr,        MarkType::kDoxygen }
1434         , { nullptr,        MarkType::kDuration }
1435         , { &fIEnumMap,     MarkType::kEnum }
1436         , { &fIEnumMap,     MarkType::kEnumClass }
1437         , { nullptr,        MarkType::kExample }
1438         , { nullptr,        MarkType::kExperimental }
1439         , { nullptr,        MarkType::kExternal }
1440         , { nullptr,        MarkType::kFile }
1441         , { nullptr,        MarkType::kFormula }
1442         , { nullptr,        MarkType::kFunction }
1443         , { nullptr,        MarkType::kHeight }
1444 		, { nullptr,        MarkType::kImage }
1445 		, { nullptr,        MarkType::kIn }
1446 		, { nullptr,        MarkType::kLegend }
1447 		, { nullptr,        MarkType::kLine }
1448 		, { nullptr,        MarkType::kLink }
1449         , { nullptr,        MarkType::kList }
1450         , { nullptr,        MarkType::kLiteral }
1451         , { nullptr,        MarkType::kMarkChar }
1452         , { nullptr,        MarkType::kMember }
1453         , { nullptr,        MarkType::kMethod }
1454         , { nullptr,        MarkType::kNoExample }
1455         , { nullptr,        MarkType::kOutdent }
1456         , { nullptr,        MarkType::kParam }
1457         , { nullptr,        MarkType::kPlatform }
1458         , { nullptr,        MarkType::kPopulate }
1459         , { nullptr,        MarkType::kPrivate }
1460         , { nullptr,        MarkType::kReturn }
1461         , { nullptr,        MarkType::kRoot }
1462         , { nullptr,        MarkType::kRow }
1463         , { nullptr,        MarkType::kSeeAlso }
1464         , { nullptr,        MarkType::kSet }
1465         , { nullptr,        MarkType::kStdOut }
1466         , { &fIStructMap,   MarkType::kStruct }
1467         , { nullptr,        MarkType::kSubstitute }
1468         , { nullptr,        MarkType::kSubtopic }
1469         , { nullptr,        MarkType::kTable }
1470         , { &fITemplateMap, MarkType::kTemplate }
1471         , { nullptr,        MarkType::kText }
1472         , { nullptr,        MarkType::kTime }
1473         , { nullptr,        MarkType::kToDo }
1474         , { nullptr,        MarkType::kTopic }
1475         , { nullptr,        MarkType::kTrack }
1476         , { &fITypedefMap,  MarkType::kTypedef }
1477         , { &fIUnionMap,    MarkType::kUnion }
1478         , { nullptr,        MarkType::kVolatile }
1479         , { nullptr,        MarkType::kWidth } }
1480     {
1481         this->reset();
1482     }
1483 
~IncludeParser()1484     ~IncludeParser() override {}
1485 
1486     void addKeyword(KeyWord keyWord);
1487 
addPunctuation(Punctuation punctuation)1488     void addPunctuation(Punctuation punctuation) {
1489         fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent);
1490     }
1491 
addWord()1492     void addWord() {
1493         fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent);
1494         fIncludeWord = nullptr;
1495     }
1496 
1497     void checkForMissingParams(const vector<string>& methodParams,
1498                                const vector<string>& foundParams);
1499     bool checkForWord();
1500     string className() const;
1501     bool crossCheck(BmhParser& );
1502     IClassDefinition* defineClass(const Definition& includeDef, const string& className);
1503     void dumpClassTokens(IClassDefinition& classDef);
1504     void dumpComment(const Definition& );
1505     void dumpEnum(const Definition& , const string& name);
1506     void dumpMethod(const Definition& );
1507     void dumpMember(const Definition& );
1508     bool dumpTokens(const string& directory);
1509     bool dumpTokens(const string& directory, const string& skClassName);
1510     bool findComments(const Definition& includeDef, Definition* markupDef);
1511 
findIncludeObject(const Definition & includeDef,MarkType markType,const string & typeName)1512     Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
1513             const string& typeName) {
1514         typedef Definition* DefinitionPtr;
1515         unordered_map<string, Definition>* map = fMaps[(int) markType].fInclude;
1516         if (!map) {
1517             return reportError<DefinitionPtr>("invalid mark type");
1518         }
1519         string name = this->uniqueName(*map, typeName);
1520         Definition& markupDef = (*map)[name];
1521         if (markupDef.fStart) {
1522             return reportError<DefinitionPtr>("definition already defined");
1523         }
1524         markupDef.fFileName = fFileName;
1525         markupDef.fStart = includeDef.fStart;
1526         markupDef.fContentStart = includeDef.fStart;
1527         markupDef.fName = name;
1528         markupDef.fContentEnd = includeDef.fContentEnd;
1529         markupDef.fTerminator = includeDef.fTerminator;
1530         markupDef.fParent = fParent;
1531         markupDef.fLineCount = includeDef.fLineCount;
1532         markupDef.fMarkType = markType;
1533         markupDef.fKeyWord = includeDef.fKeyWord;
1534         markupDef.fType = Definition::Type::kMark;
1535         return &markupDef;
1536     }
1537 
1538     static KeyWord FindKey(const char* start, const char* end);
1539     bool internalName(const Definition& ) const;
1540     bool parseChar();
1541     bool parseComment(const string& filename, const char* start, const char* end, int lineCount,
1542             Definition* markupDef);
1543     bool parseClass(Definition* def, IsStruct);
1544     bool parseDefine();
1545     bool parseEnum(Definition* child, Definition* markupDef);
1546 
parseFromFile(const char * path)1547     bool parseFromFile(const char* path) override {
1548         this->reset();
1549         if (!INHERITED::parseSetup(path)) {
1550             return false;
1551         }
1552         string name(path);
1553         return this->parseInclude(name);
1554     }
1555 
1556     bool parseInclude(const string& name);
1557     bool parseMember(Definition* child, Definition* markupDef);
1558     bool parseMethod(Definition* child, Definition* markupDef);
1559     bool parseObject(Definition* child, Definition* markupDef);
1560     bool parseObjects(Definition* parent, Definition* markupDef);
1561     bool parseTemplate();
1562     bool parseTypedef(Definition* child, Definition* markupDef);
1563     bool parseUnion();
1564 
popBracket()1565     void popBracket() {
1566         SkASSERT(Definition::Type::kBracket == fParent->fType);
1567         this->popObject();
1568         Bracket bracket = this->topBracket();
1569         this->setBracketShortCuts(bracket);
1570     }
1571 
pushBracket(Bracket bracket)1572     void pushBracket(Bracket bracket) {
1573         this->setBracketShortCuts(bracket);
1574         fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent);
1575         Definition* container = &fParent->fTokens.back();
1576         this->addDefinition(container);
1577     }
1578 
1579     static void RemoveFile(const char* docs, const char* includes);
1580     static void RemoveOneFile(const char* docs, const char* includesFileOrPath);
1581 
reset()1582     void reset() override {
1583         INHERITED::resetCommon();
1584         fRootTopic = nullptr;
1585         fInBrace = nullptr;
1586         fIncludeWord = nullptr;
1587         fLastObject = nullptr;
1588         fPrev = '\0';
1589         fInChar = false;
1590         fInCharCommentString = false;
1591         fInComment = false;
1592         fInEnum = false;
1593         fInFunction = false;
1594         fInString = false;
1595         fFailed = false;
1596         fPriorEnum = nullptr;
1597     }
1598 
setBracketShortCuts(Bracket bracket)1599     void setBracketShortCuts(Bracket bracket) {
1600         fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket;
1601         fInString = Bracket::kString == bracket;
1602         fInChar = Bracket::kChar == bracket;
1603         fInCharCommentString = fInChar || fInComment || fInString;
1604     }
1605 
topBracket()1606     Bracket topBracket() const {
1607         Definition* parent = fParent;
1608         while (parent && Definition::Type::kBracket != parent->fType) {
1609             parent = parent->fParent;
1610         }
1611         return parent ? parent->fBracket : Bracket::kNone;
1612     }
1613 
1614     template <typename T>
uniqueName(const unordered_map<string,T> & m,const string & typeName)1615     string uniqueName(const unordered_map<string, T>& m, const string& typeName) {
1616         string base(typeName.size() > 0 ? typeName : "_anonymous");
1617         string name(base);
1618         int anonCount = 1;
1619         do {
1620             auto iter = m.find(name);
1621             if (iter == m.end()) {
1622                 return name;
1623             }
1624             name = base + '_';
1625             name += to_string(++anonCount);
1626         } while (true);
1627         // should never get here
1628         return string();
1629     }
1630 
1631     void validate() const;
1632 
writeDefinition(const Definition & def)1633     void writeDefinition(const Definition& def) {
1634         if (def.length() > 1) {
1635             this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1636             this->lf(1);
1637         }
1638     }
1639 
writeDefinition(const Definition & def,const string & name,int spaces)1640     void writeDefinition(const Definition& def, const string& name, int spaces) {
1641         this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1642         this->writeSpace(spaces);
1643         this->writeString(name);
1644         this->lf(1);
1645     }
1646 
writeEndTag()1647     void writeEndTag() {
1648         this->lf(1);
1649         this->writeString("##");
1650         this->lf(1);
1651     }
1652 
writeEndTag(const char * tagType)1653     void writeEndTag(const char* tagType) {
1654         this->lf(1);
1655         this->writeString(string("#") + tagType + " ##");
1656         this->lf(1);
1657     }
1658 
1659     void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) {
1660         this->lf(1);
1661         this->writeString(string("#") + tagType + " " + tagID);
1662         this->writeSpace(spaces);
1663         this->writeString("##");
1664         this->lf(1);
1665     }
1666 
1667     void writeEndTag(const char* tagType, const string& tagID, int spaces = 1) {
1668         this->writeEndTag(tagType, tagID.c_str(), spaces);
1669     }
1670 
1671     void writeIncompleteTag(const char* tagType, const string& tagID, int spaces = 1) {
1672         this->writeString(string("#") + tagType + " " + tagID);
1673         this->writeSpace(spaces);
1674         this->writeString("incomplete");
1675         this->writeSpace();
1676         this->writeString("##");
1677         this->lf(1);
1678     }
1679 
writeIncompleteTag(const char * tagType)1680     void writeIncompleteTag(const char* tagType) {
1681         this->writeString(string("#") + tagType + " incomplete ##");
1682         this->lf(1);
1683     }
1684 
writeTableHeader(const char * col1,size_t pad,const char * col2)1685     void writeTableHeader(const char* col1, size_t pad, const char* col2) {
1686         this->lf(1);
1687         this->writeString("#Table");
1688         this->lf(1);
1689         this->writeString("#Legend");
1690         this->lf(1);
1691         string legend = "# ";
1692         legend += col1;
1693         if (pad > strlen(col1)) {
1694             legend += string(pad - strlen(col1), ' ');
1695         }
1696         legend += " # ";
1697         legend += col2;
1698         legend += " ##";
1699         this->writeString(legend);
1700         this->lf(1);
1701         this->writeString("#Legend ##");
1702         this->lf(1);
1703     }
1704 
writeTableRow(size_t pad,const string & col1)1705     void writeTableRow(size_t pad, const string& col1) {
1706         this->lf(1);
1707         string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##";
1708         this->writeString(row);
1709         this->lf(1);
1710     }
1711 
writeTableRow(size_t pad1,const string & col1,size_t pad2,const string & col2)1712     void writeTableRow(size_t pad1, const string& col1, size_t pad2, const string& col2) {
1713         this->lf(1);
1714         string row = "# " + col1 + string(pad1 - col1.length(), ' ') + " # " +
1715                 col2 + string(pad2 - col2.length(), ' ') + " ##";
1716         this->writeString(row);
1717         this->lf(1);
1718     }
1719 
writeTableTrailer()1720     void writeTableTrailer() {
1721         this->lf(1);
1722         this->writeString("#Table ##");
1723         this->lf(1);
1724     }
1725 
writeTag(const char * tagType)1726     void writeTag(const char* tagType) {
1727         this->lf(1);
1728         this->writeString("#");
1729         this->writeString(tagType);
1730     }
1731 
writeTagNoLF(const char * tagType,const char * tagID)1732     void writeTagNoLF(const char* tagType, const char* tagID) {
1733         this->writeString("#");
1734         this->writeString(tagType);
1735         this->writeSpace();
1736         this->writeString(tagID);
1737     }
1738 
writeTagNoLF(const char * tagType,const string & tagID)1739     void writeTagNoLF(const char* tagType, const string& tagID) {
1740         this->writeTagNoLF(tagType, tagID.c_str());
1741     }
1742 
writeTag(const char * tagType,const char * tagID)1743     void writeTag(const char* tagType, const char* tagID) {
1744         this->lf(1);
1745         this->writeTagNoLF(tagType, tagID);
1746     }
1747 
writeTag(const char * tagType,const string & tagID)1748     void writeTag(const char* tagType, const string& tagID) {
1749         this->writeTag(tagType, tagID.c_str());
1750     }
1751 
1752 protected:
1753     static void ValidateKeyWords();
1754 
1755     struct DefinitionMap {
1756         unordered_map<string, Definition>* fInclude;
1757         MarkType fMarkType;
1758     };
1759 
1760     DefinitionMap fMaps[Last_MarkType + 1];
1761     unordered_map<string, Definition> fIncludeMap;
1762     unordered_map<string, IClassDefinition> fIClassMap;
1763     unordered_map<string, Definition> fIDefineMap;
1764     unordered_map<string, Definition> fIEnumMap;
1765     unordered_map<string, Definition> fIFunctionMap;
1766     unordered_map<string, Definition> fIStructMap;
1767     unordered_map<string, Definition> fITemplateMap;
1768     unordered_map<string, Definition> fITypedefMap;
1769     unordered_map<string, Definition> fIUnionMap;
1770     Definition* fRootTopic;
1771     Definition* fInBrace;
1772     Definition* fLastObject;
1773     Definition* fPriorEnum;
1774     int fPriorIndex;
1775     const char* fIncludeWord;
1776     char fPrev;
1777     bool fInChar;
1778     bool fInCharCommentString;
1779     bool fInComment;
1780     bool fInEnum;
1781     bool fInFunction;
1782     bool fInString;
1783     bool fFailed;
1784 
1785     typedef ParserCommon INHERITED;
1786 };
1787 
1788 class IncludeWriter : public IncludeParser {
1789 public:
1790     enum class Word {
1791         kStart,
1792         kCap,
1793         kFirst,
1794         kUnderline,
1795         kMixed,
1796     };
1797 
1798     enum class Phrase {
1799         kNo,
1800         kYes,
1801     };
1802 
1803     enum class PunctuationState {
1804         kStart,
1805         kDelimiter,
1806         kPeriod,
1807         kSpace,
1808     };
1809 
1810     enum class RefType {
1811         kUndefined,
1812         kNormal,
1813         kExternal,
1814     };
1815 
1816     enum class Wrote {
1817         kNone,
1818         kLF,
1819         kChars,
1820     };
1821 
1822     struct IterState {
IterStateIterState1823         IterState (list<Definition>::iterator tIter, list<Definition>::iterator tIterEnd)
1824             : fDefIter(tIter)
1825             , fDefEnd(tIterEnd) {
1826         }
1827         list<Definition>::iterator fDefIter;
1828         list<Definition>::iterator fDefEnd;
1829     };
1830 
1831     struct ParentPair {
1832         const Definition* fParent;
1833         const ParentPair* fPrev;
1834     };
1835 
IncludeWriter()1836     IncludeWriter() : IncludeParser() {
1837         this->reset();
1838     }
1839 
~IncludeWriter()1840     ~IncludeWriter() override {}
1841 
contentFree(int size,const char * data)1842     bool contentFree(int size, const char* data) const {
1843         while (size > 0 && data[0] <= ' ') {
1844             --size;
1845             ++data;
1846         }
1847         while (size > 0 && data[size - 1] <= ' ') {
1848             --size;
1849         }
1850         return 0 == size;
1851     }
1852 
1853     void descriptionOut(const Definition* def);
1854     void enumHeaderOut(const RootDefinition* root, const Definition& child);
1855     void enumMembersOut(const RootDefinition* root, Definition& child);
1856     void enumSizeItems(const Definition& child);
1857 	Definition* findMemberCommentBlock(const vector<Definition*>& bmhChildren, const string& name) const;
1858     int lookupMethod(const PunctuationState punctuation, const Word word,
1859             const int start, const int run, int lastWrite,
1860             const char* data, bool hasIndirection);
1861     int lookupReference(const PunctuationState punctuation, const Word word,
1862             const int start, const int run, int lastWrite, const char last,
1863             const char* data);
1864     void methodOut(const Definition* method, const Definition& child);
1865     bool populate(Definition* def, ParentPair* parentPair, RootDefinition* root);
1866     bool populate(BmhParser& bmhParser);
1867 
reset()1868     void reset() override {
1869         INHERITED::resetCommon();
1870         fBmhMethod = nullptr;
1871         fBmhParser = nullptr;
1872         fEnumDef = nullptr;
1873         fMethodDef = nullptr;
1874         fBmhStructDef = nullptr;
1875         fAttrDeprecated = nullptr;
1876         fInStruct = false;
1877         fWroteMethod = false;
1878         fIndentNext = false;
1879         fPendingMethod = false;
1880     }
1881 
1882     string resolveMethod(const char* start, const char* end, bool first);
1883     string resolveRef(const char* start, const char* end, bool first, RefType* refType);
1884     Wrote rewriteBlock(int size, const char* data, Phrase phrase);
1885     Definition* structMemberOut(const Definition* memberStart, const Definition& child);
1886     void structOut(const Definition* root, const Definition& child,
1887             const char* commentStart, const char* commentEnd);
1888     void structSizeMembers(const Definition& child);
1889 private:
1890     BmhParser* fBmhParser;
1891     Definition* fDeferComment;
1892     Definition* fLastComment;
1893     const Definition* fBmhMethod;
1894     const Definition* fEnumDef;
1895     const Definition* fMethodDef;
1896     const Definition* fBmhStructDef;
1897     const Definition* fAttrDeprecated;
1898     const char* fContinuation;  // used to construct paren-qualified method name
1899     int fAnonymousEnumCount;
1900     int fEnumItemValueTab;
1901     int fEnumItemCommentTab;
1902     int fStructMemberTab;
1903     int fStructValueTab;
1904     int fStructCommentTab;
1905     bool fInStruct;
1906     bool fWroteMethod;
1907     bool fIndentNext;
1908     bool fPendingMethod;
1909 
1910     typedef IncludeParser INHERITED;
1911 };
1912 
1913 class FiddleBase : public ParserCommon {
1914 protected:
FiddleBase(BmhParser * bmh)1915     FiddleBase(BmhParser* bmh) : ParserCommon()
1916         , fBmhParser(bmh)
1917         , fContinuation(false)
1918         , fTextOut(false)
1919         , fPngOut(false)
1920     {
1921         this->reset();
1922     }
1923 
reset()1924     void reset() override {
1925         INHERITED::resetCommon();
1926     }
1927 
1928     Definition* findExample(const string& name) const;
1929     bool parseFiddles();
1930     virtual bool pngOut(Definition* example) = 0;
1931     virtual bool textOut(Definition* example, const char* stdOutStart,
1932         const char* stdOutEnd) = 0;
1933 
1934     BmhParser* fBmhParser;  // must be writable; writes example hash
1935     string fFullName;
1936     bool fContinuation;
1937     bool fTextOut;
1938     bool fPngOut;
1939 private:
1940     typedef ParserCommon INHERITED;
1941 };
1942 
1943 class FiddleParser : public FiddleBase {
1944 public:
FiddleParser(BmhParser * bmh)1945     FiddleParser(BmhParser* bmh) : FiddleBase(bmh) {
1946        fTextOut = true;
1947     }
1948 
parseFromFile(const char * path)1949     bool parseFromFile(const char* path) override {
1950         if (!INHERITED::parseSetup(path)) {
1951             return false;
1952         }
1953         return parseFiddles();
1954     }
1955 
1956 private:
pngOut(Definition * example)1957     bool pngOut(Definition* example) override {
1958         return true;
1959     }
1960 
1961     bool textOut(Definition* example, const char* stdOutStart,
1962         const char* stdOutEnd) override;
1963 
1964     typedef FiddleBase INHERITED;
1965 };
1966 
1967 class Catalog : public FiddleBase {
1968 public:
Catalog(BmhParser * bmh)1969     Catalog(BmhParser* bmh) : FiddleBase(bmh) {}
1970 
1971     bool appendFile(const string& path);
1972     bool closeCatalog();
1973     bool openCatalog(const char* inDir, const char* outDir);
1974     bool openStatus(const char* inDir, const char* outDir);
1975 
1976     bool parseFromFile(const char* path) override ;
1977 private:
1978     bool pngOut(Definition* example) override;
1979     bool textOut(Definition* example, const char* stdOutStart,
1980         const char* stdOutEnd) override;
1981 
1982     string fDocsDir;
1983 
1984     typedef FiddleBase INHERITED;
1985 };
1986 
1987 class HackParser : public ParserCommon {
1988 public:
HackParser(const BmhParser & bmhParser)1989     HackParser(const BmhParser& bmhParser)
1990         : ParserCommon()
1991         , fBmhParser(bmhParser) {
1992         this->reset();
1993     }
1994 
1995     void addOneLiner(const Definition* defTable, const Definition* child, bool hasLine,
1996             bool lfAfter);
1997 
parseFromFile(const char * path)1998     bool parseFromFile(const char* path) override {
1999         if (!INHERITED::parseSetup(path)) {
2000             return false;
2001         }
2002         return hackFiles();
2003     }
2004 
reset()2005     void reset() override {
2006         INHERITED::resetCommon();
2007     }
2008 
2009     string searchTable(const Definition* tableHolder, const Definition* match);
2010 
2011     void topicIter(const Definition* );
2012 
2013 private:
2014     const BmhParser& fBmhParser;
2015     const Definition* fClassesAndStructs;
2016     const Definition* fConstants;
2017     const Definition* fConstructors;
2018     const Definition* fMemberFunctions;
2019     const Definition* fMembers;
2020     const Definition* fOperators;
2021     const Definition* fRelatedFunctions;
2022     bool hackFiles();
2023 
2024     typedef ParserCommon INHERITED;
2025 };
2026 
2027 class MdOut : public ParserCommon {
2028 public:
MdOut(const BmhParser & bmh)2029     MdOut(const BmhParser& bmh) : ParserCommon()
2030         , fBmhParser(bmh) {
2031         this->reset();
2032     }
2033 
2034     bool buildReferences(const char* docDir, const char* mdOutDirOrFile);
2035     bool buildStatus(const char* docDir, const char* mdOutDir);
2036 
2037     static constexpr const char* kClassesAndStructs = "Classes_and_Structs";
2038     static constexpr const char* kConstants = "Constants";
2039     static constexpr const char* kConstructors = "Constructors";
2040     static constexpr const char* kMemberFunctions = "Member_Functions";
2041     static constexpr const char* kMembers = "Members";
2042     static constexpr const char* kOperators = "Operators";
2043     static constexpr const char* kOverview = "Overview";
2044     static constexpr const char* kRelatedFunctions = "Related_Functions";
2045     static constexpr const char* kSubtopics = "Subtopics";
2046 
2047 private:
2048     enum class TableState {
2049         kNone,
2050         kRow,
2051         kColumn,
2052     };
2053 
2054     string addReferences(const char* start, const char* end, BmhParser::Resolvable );
2055     bool buildRefFromFile(const char* fileName, const char* outDir);
2056     bool checkParamReturnBody(const Definition* def) const;
2057     void childrenOut(const Definition* def, const char* contentStart);
2058     const Definition* csParent() const;
2059     const Definition* findParamType();
2060     const Definition* isDefined(const TextParser& parser, const string& ref, bool report) const;
2061     string linkName(const Definition* ) const;
2062     string linkRef(const string& leadingSpaces, const Definition*, const string& ref,
2063 			BmhParser::Resolvable ) const;
2064     void markTypeOut(Definition* );
mdHeaderOut(int depth)2065     void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); }
2066     void mdHeaderOutLF(int depth, int lf);
2067     void overviewOut();
parseFromFile(const char * path)2068     bool parseFromFile(const char* path) override { return true; }
2069     void populateTables(const Definition* def);
2070 
populator(const char * key)2071     vector<const Definition*>& populator(const char* key) {
2072         return fPopulators.find(key)->second.fMembers;
2073     }
2074 
reset()2075     void reset() override {
2076         INHERITED::resetCommon();
2077         fEnumClass = nullptr;
2078         fMethod = nullptr;
2079         fRoot = nullptr;
2080         fLastParam = nullptr;
2081         fTableState = TableState::kNone;
2082         fHasFiddle = false;
2083         fInDescription = false;
2084         fInList = false;
2085         fRespectLeadingSpace = false;
2086     }
2087 
resolvable(const Definition * definition)2088     BmhParser::Resolvable resolvable(const Definition* definition) const {
2089         MarkType markType = definition->fMarkType;
2090         if (MarkType::kCode == markType) {
2091             for (auto child : definition->fChildren) {
2092                 if (MarkType::kLiteral == child->fMarkType) {
2093                     return BmhParser::Resolvable::kLiteral;
2094                 }
2095             }
2096         }
2097         if ((MarkType::kExample == markType
2098                 || MarkType::kFunction == markType) && fHasFiddle) {
2099             return BmhParser::Resolvable::kNo;
2100         }
2101         return fBmhParser.fMaps[(int) markType].fResolve;
2102     }
2103 
2104     void resolveOut(const char* start, const char* end, BmhParser::Resolvable );
2105     void rowOut(const char * name, const string& description);
2106     void subtopicOut(vector<const Definition*>& data);
2107     void subtopicsOut();
2108 
2109     struct TableContents {
2110         string fDescription;
2111         vector<const Definition*> fMembers;
2112     };
2113 
2114     unordered_map<string, TableContents> fPopulators;
2115     vector<const Definition*> fClassStack;
2116 
2117     const BmhParser& fBmhParser;
2118     const Definition* fEnumClass;
2119     Definition* fMethod;
2120     const RootDefinition* fRoot;
2121     const Definition* fLastParam;
2122     TableState fTableState;
2123     bool fHasFiddle;
2124     bool fInDescription;   // FIXME: for now, ignore unfound camelCase in description since it may
2125                            // be defined in example which at present cannot be linked to
2126     bool fInList;
2127     bool fRespectLeadingSpace;
2128     typedef ParserCommon INHERITED;
2129 };
2130 
2131 
2132 // some methods cannot be trivially parsed; look for class-name / ~ / operator
2133 class MethodParser : public TextParser {
2134 public:
MethodParser(const string & className,const string & fileName,const char * start,const char * end,int lineCount)2135     MethodParser(const string& className, const string& fileName,
2136             const char* start, const char* end, int lineCount)
2137         : TextParser(fileName, start, end, lineCount)
2138         , fClassName(className) {
2139     }
2140 
~MethodParser()2141     ~MethodParser() override {}
2142 
skipToMethodStart()2143     void skipToMethodStart() {
2144         if (!fClassName.length()) {
2145             this->skipToAlphaNum();
2146             return;
2147         }
2148         while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
2149             this->next();
2150         }
2151     }
2152 
skipToMethodEnd()2153     void skipToMethodEnd() {
2154         if (this->eof()) {
2155             return;
2156         }
2157         if (fClassName.length()) {
2158             if ('~' == this->peek()) {
2159                 this->next();
2160                 if (!this->startsWith(fClassName.c_str())) {
2161                     --fChar;
2162                     return;
2163                 }
2164             }
2165             if (this->startsWith(fClassName.c_str()) || this->startsWith("operator")) {
2166                 const char* ptr = this->anyOf("\n (");
2167                 if (ptr && '(' ==  *ptr) {
2168                     this->skipToEndBracket(')');
2169                     SkAssertResult(')' == this->next());
2170                     this->skipExact("_const");
2171                     return;
2172                 }
2173             }
2174         }
2175         if (this->startsWith("Sk") && this->wordEndsWith(".h")) {  // allow include refs
2176             this->skipToNonAlphaNum();
2177         } else {
2178             this->skipFullName();
2179             if (this->endsWith("operator")) {
2180                 const char* ptr = this->anyOf("\n (");
2181                 if (ptr && '(' ==  *ptr) {
2182                     this->skipToEndBracket(')');
2183                     SkAssertResult(')' == this->next());
2184                     this->skipExact("_const");
2185                 }
2186             }
2187         }
2188     }
2189 
wordEndsWith(const char * str)2190     bool wordEndsWith(const char* str) const {
2191         const char* space = this->strnchr(' ', fEnd);
2192         if (!space) {
2193             return false;
2194         }
2195         size_t len = strlen(str);
2196         if (space < fChar + len) {
2197             return false;
2198         }
2199         return !strncmp(str, space - len, len);
2200     }
2201 
2202 private:
2203     string fClassName;
2204     typedef TextParser INHERITED;
2205 };
2206 
2207 bool SelfCheck(const BmhParser& );
2208 
2209 #endif
2210