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