blob: f5f53ff7ab683facbe2649f07a9b67059235a676 [file] [log] [blame]
Cary Clark8032b982017-07-28 11:04:54 -04001/*
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
Cary Clarkce101242017-09-01 15:51:02 -040011#include "SkCommandLineFlags.h"
Cary Clark8032b982017-07-28 11:04:54 -040012#include "SkData.h"
13
Ben Wagner63fd7602017-10-09 15:45:33 -040014#include <algorithm>
Cary Clark8032b982017-07-28 11:04:54 -040015#include <cmath>
16#include <cctype>
17#include <forward_list>
18#include <list>
19#include <string>
20#include <unordered_map>
21#include <vector>
22
23// std::to_string isn't implemented on android
24#include <sstream>
25
26template <typename T>
27std::string to_string(T value)
28{
29 std::ostringstream os ;
30 os << value ;
31 return os.str() ;
32}
33
34using std::forward_list;
35using std::list;
36using std::unordered_map;
37using std::string;
38using std::vector;
39
40enum class KeyWord {
41 kNone,
Cary Clark73fa9722017-08-29 17:36:51 -040042 kSK_API,
Cary Clark154beea2017-10-26 07:58:48 -040043 kSK_BEGIN_REQUIRE_DENSE,
Cary Clark8032b982017-07-28 11:04:54 -040044 kBool,
45 kChar,
46 kClass,
47 kConst,
48 kConstExpr,
49 kDefine,
50 kDouble,
51 kElif,
52 kElse,
53 kEndif,
54 kEnum,
55 kFloat,
56 kFriend,
57 kIf,
58 kIfdef,
59 kIfndef,
60 kInclude,
61 kInline,
62 kInt,
63 kOperator,
64 kPrivate,
65 kProtected,
66 kPublic,
67 kSigned,
68 kSize_t,
69 kStatic,
70 kStruct,
71 kTemplate,
72 kTypedef,
Cary Clarkd0530ba2017-09-14 11:25:39 -040073 kUint16_t,
Cary Clark8032b982017-07-28 11:04:54 -040074 kUint32_t,
Cary Clarkd0530ba2017-09-14 11:25:39 -040075 kUint64_t,
76 kUint8_t,
Cary Clark8032b982017-07-28 11:04:54 -040077 kUnion,
78 kUnsigned,
79 kVoid,
80};
81
82enum class MarkType {
83 kNone,
84 kAnchor,
85 kAlias,
86 kBug,
87 kClass,
88 kCode,
89 kColumn,
90 kComment,
91 kConst,
92 kDefine,
93 kDefinedBy,
94 kDeprecated,
95 kDescription,
96 kDoxygen,
97 kEnum,
98 kEnumClass,
99 kError,
100 kExample,
101 kExperimental,
102 kExternal,
103 kFile,
104 kFormula,
105 kFunction,
106 kHeight,
107 kImage,
108 kLegend,
109 kLink,
110 kList,
Cary Clark154beea2017-10-26 07:58:48 -0400111 kLiteral, // don't lookup hyperlinks, do substitution, etc
Cary Clark8032b982017-07-28 11:04:54 -0400112 kMarkChar,
113 kMember,
114 kMethod,
115 kNoExample,
Cary Clark154beea2017-10-26 07:58:48 -0400116 kOutdent,
Cary Clark8032b982017-07-28 11:04:54 -0400117 kParam,
118 kPlatform,
119 kPrivate,
120 kReturn,
121 kRoot,
122 kRow,
123 kSeeAlso,
124 kStdOut,
125 kStruct,
126 kSubstitute,
127 kSubtopic,
128 kTable,
129 kTemplate,
130 kText,
131 kTime,
132 kToDo,
133 kTopic,
134 kTrack,
135 kTypedef,
136 kUnion,
137 kVolatile,
138 kWidth,
139};
140
141enum {
142 Last_MarkType = (int) MarkType::kWidth,
143};
144
145enum class Bracket {
146 kNone,
147 kParen,
148 kSquare,
149 kBrace,
150 kAngle,
151 kString,
152 kChar,
153 kSlashStar,
154 kSlashSlash,
155 kPound,
156 kColon,
Cary Clark73fa9722017-08-29 17:36:51 -0400157 kDebugCode, // parens get special treatment so SkDEBUGCODE( isn't treated as method
Cary Clark8032b982017-07-28 11:04:54 -0400158};
159
160enum class Punctuation { // catch-all for misc symbols tracked in C
161 kNone,
162 kAsterisk, // for pointer-to
163 kSemicolon, // e.g., to delinate xxx() const ; const int* yyy()
164 kLeftBrace,
165 kColon, // for foo() : bar(1), baz(2) {}
166};
167
Cary Clarkd0530ba2017-09-14 11:25:39 -0400168enum class KeyProperty {
169 kNone,
170 kClassSection,
171 kFunction,
172 kModifier,
173 kNumber,
174 kObject,
175 kPreprocessor,
176};
177
178struct IncludeKey {
179 const char* fName;
180 KeyWord fKeyWord;
181 KeyProperty fProperty;
182};
183
184extern const IncludeKey kKeyWords[];
185
Cary Clark8032b982017-07-28 11:04:54 -0400186static inline bool has_nonwhitespace(const string& s) {
187 bool nonwhite = false;
188 for (const char& c : s) {
189 if (' ' < c) {
190 nonwhite = true;
191 break;
192 }
193 }
194 return nonwhite;
195}
196
197static inline void trim_end(string &s) {
198 s.erase(std::find_if(s.rbegin(), s.rend(),
199 std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
200}
201
202static inline void trim_end_spaces(string &s) {
203 while (s.length() > 0 && ' ' == s.back()) {
204 s.pop_back();
205 }
206}
207
208static inline void trim_start(string &s) {
209 s.erase(s.begin(), std::find_if(s.begin(), s.end(),
210 std::not1(std::ptr_fun<int, int>(std::isspace))));
211}
212
213static inline void trim_start_end(string& s) {
214 trim_start(s);
215 trim_end(s);
216}
217
218class NonAssignable {
219public:
220 NonAssignable(NonAssignable const&) = delete;
221 NonAssignable& operator=(NonAssignable const&) = delete;
222 NonAssignable() {}
223};
224
225class Definition;
226
227class TextParser : public NonAssignable {
228 TextParser() {} // only for ParserCommon to call
229 friend class ParserCommon;
230public:
Cary Clark8032b982017-07-28 11:04:54 -0400231 class Save {
232 public:
233 Save(TextParser* parser) {
234 fParser = parser;
235 fLine = parser->fLine;
236 fChar = parser->fChar;
237 fLineCount = parser->fLineCount;
238 }
239
240 void restore() const {
241 fParser->fLine = fLine;
242 fParser->fChar = fChar;
243 fParser->fLineCount = fLineCount;
244 }
245
246 private:
247 TextParser* fParser;
248 const char* fLine;
249 const char* fChar;
250 int fLineCount;
251 };
252
253 TextParser(const string& fileName, const char* start, const char* end, int lineCount)
254 : fFileName(fileName)
255 , fStart(start)
256 , fLine(start)
257 , fChar(start)
258 , fEnd(end)
259 , fLineCount(lineCount)
260 {
261 }
262
263 TextParser(const Definition* );
264
265 const char* anyOf(const char* str) const {
266 const char* ptr = fChar;
267 while (ptr < fEnd) {
268 if (strchr(str, ptr[0])) {
269 return ptr;
270 }
271 ++ptr;
272 }
273 return nullptr;
274 }
275
276 const char* anyOf(const char* wordStart, const char* wordList[], size_t wordListCount) const {
277 const char** wordPtr = wordList;
278 const char** wordEnd = wordPtr + wordListCount;
279 const size_t matchLen = fChar - wordStart;
280 while (wordPtr < wordEnd) {
281 const char* word = *wordPtr++;
282 if (strlen(word) == matchLen && !strncmp(wordStart, word, matchLen)) {
283 return word;
284 }
285 }
286 return nullptr;
287 }
288
289 char backup(const char* pattern) const {
290 size_t len = strlen(pattern);
291 const char* start = fChar - len;
292 if (start <= fStart) {
293 return '\0';
294 }
295 if (strncmp(start, pattern, len)) {
296 return '\0';
297 }
298 return start[-1];
299 }
300
301 bool contains(const char* match, const char* lineEnd, const char** loc) const {
302 *loc = this->strnstr(match, lineEnd);
303 return *loc;
304 }
305
306 bool eof() const { return fChar >= fEnd; }
307
308 const char* lineEnd() const {
309 const char* ptr = fChar;
310 do {
311 if (ptr >= fEnd) {
312 return ptr;
313 }
314 char test = *ptr++;
315 if (test == '\n' || test == '\0') {
316 break;
317 }
318 } while (true);
319 return ptr;
320 }
321
322 ptrdiff_t lineLength() const {
323 return this->lineEnd() - fLine;
324 }
325
326 bool match(TextParser* );
327
Ben Wagner63fd7602017-10-09 15:45:33 -0400328 char next() {
Cary Clark8032b982017-07-28 11:04:54 -0400329 SkASSERT(fChar < fEnd);
330 char result = *fChar++;
331 if ('\n' == result) {
332 ++fLineCount;
333 fLine = fChar;
334 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400335 return result;
Cary Clark8032b982017-07-28 11:04:54 -0400336 }
337
338 char peek() const { SkASSERT(fChar < fEnd); return *fChar; }
339
340 void restorePlace(const TextParser& save) {
341 fChar = save.fChar;
342 fLine = save.fLine;
343 fLineCount = save.fLineCount;
344 }
345
346 void savePlace(TextParser* save) {
347 save->fChar = fChar;
348 save->fLine = fLine;
349 save->fLineCount = fLineCount;
350 }
351
352 void reportError(const char* errorStr) const;
353 void reportWarning(const char* errorStr) const;
354
355 template <typename T> T reportError(const char* errorStr) const {
356 this->reportError(errorStr);
357 return T();
358 }
359
360 bool sentenceEnd(const char* check) const {
361 while (check > fStart) {
362 --check;
363 if (' ' < check[0] && '.' != check[0]) {
364 return false;
365 }
366 if ('.' == check[0]) {
367 return ' ' >= check[1];
368 }
369 if ('\n' == check[0] && '\n' == check[1]) {
370 return true;
371 }
372 }
373 return true;
374 }
375
376 bool skipToEndBracket(char endBracket, const char* end = nullptr) {
377 if (nullptr == end) {
378 end = fEnd;
379 }
380 while (fChar[0] != endBracket) {
381 if (fChar >= end) {
382 return false;
383 }
384 (void) this->next();
385 }
386 return true;
387 }
388
389 bool skipToEndBracket(const char* endBracket) {
390 size_t len = strlen(endBracket);
391 while (strncmp(fChar, endBracket, len)) {
392 if (fChar >= fEnd) {
393 return false;
394 }
395 (void) this->next();
396 }
397 return true;
398 }
399
400 bool skipLine() {
401 return skipToEndBracket('\n');
402 }
403
404 void skipTo(const char* skip) {
405 while (fChar < skip) {
406 this->next();
407 }
408 }
409
410 void skipToAlpha() {
411 while (fChar < fEnd && !isalpha(fChar[0])) {
412 fChar++;
413 }
414 }
415
416 void skipToAlphaNum() {
417 while (fChar < fEnd && !isalnum(fChar[0])) {
418 fChar++;
419 }
420 }
421
422 bool skipExact(const char* pattern) {
423 if (!this->startsWith(pattern)) {
424 return false;
425 }
426 this->skipName(pattern);
427 return true;
428 }
429
430 // differs from skipToNonAlphaNum in that a.b isn't considered a full name,
431 // since a.b can't be found as a named definition
432 void skipFullName() {
433 while (fChar < fEnd && (isalnum(fChar[0])
434 || '_' == fChar[0] || '-' == fChar[0]
435 || (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]))) {
436 if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
437 fChar++;
438 }
439 fChar++;
440 }
441 }
442
443 bool skipToLineStart() {
444 if (!this->skipLine()) {
445 return false;
446 }
447 if (!this->eof()) {
448 return this->skipWhiteSpace();
449 }
450 return true;
451 }
452
453 void skipToNonAlphaNum() {
454 while (fChar < fEnd && (isalnum(fChar[0])
455 || '_' == fChar[0] || '-' == fChar[0]
Cary Clarkce101242017-09-01 15:51:02 -0400456 || (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
Cary Clark8032b982017-07-28 11:04:54 -0400457 || ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
458 if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
459 fChar++;
460 }
461 fChar++;
462 }
463 }
464
465 void skipToSpace() {
466 while (fChar < fEnd && ' ' != fChar[0]) {
467 fChar++;
468 }
469 }
470
471 bool skipName(const char* word) {
472 size_t len = strlen(word);
Cary Clarkce101242017-09-01 15:51:02 -0400473 if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
Cary Clarkd0530ba2017-09-14 11:25:39 -0400474 for (size_t i = 0; i < len; ++i) {
475 this->next();
476 }
Cary Clark8032b982017-07-28 11:04:54 -0400477 }
478 return this->eof() || ' ' >= fChar[0];
479 }
480
Ben Wagner63fd7602017-10-09 15:45:33 -0400481 bool skipSpace() {
482 while (' ' == this->peek()) {
Cary Clark8032b982017-07-28 11:04:54 -0400483 (void) this->next();
484 if (fChar >= fEnd) {
485 return false;
486 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400487 }
488 return true;
Cary Clark8032b982017-07-28 11:04:54 -0400489 }
490
491 bool skipWord(const char* word) {
492 if (!this->skipWhiteSpace()) {
493 return false;
494 }
495 const char* save = fChar;
496 if (!this->skipName(word)) {
497 fChar = save;
498 return false;
499 }
500 if (!this->skipWhiteSpace()) {
501 return false;
502 }
503 return true;
504 }
505
Ben Wagner63fd7602017-10-09 15:45:33 -0400506 bool skipWhiteSpace() {
507 while (' ' >= this->peek()) {
Cary Clark8032b982017-07-28 11:04:54 -0400508 (void) this->next();
509 if (fChar >= fEnd) {
510 return false;
511 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400512 }
513 return true;
Cary Clark8032b982017-07-28 11:04:54 -0400514 }
515
516 bool startsWith(const char* str) const {
517 size_t len = strlen(str);
Ben Wagner63fd7602017-10-09 15:45:33 -0400518 ptrdiff_t lineLen = fEnd - fChar;
Cary Clark8032b982017-07-28 11:04:54 -0400519 return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
520 }
521
Cary Clarkbad5ad72017-08-03 17:14:08 -0400522 // ignores minor white space differences
523 bool startsWith(const char* str, size_t oLen) const {
524 size_t tIndex = 0;
525 size_t tLen = fEnd - fChar;
526 size_t oIndex = 0;
527 while (oIndex < oLen && tIndex < tLen) {
528 bool tSpace = ' ' >= fChar[tIndex];
529 bool oSpace = ' ' >= str[oIndex];
530 if (tSpace != oSpace) {
531 break;
532 }
533 if (tSpace) {
534 do {
535 ++tIndex;
536 } while (tIndex < tLen && ' ' >= fChar[tIndex]);
537 do {
538 ++oIndex;
539 } while (oIndex < oLen && ' ' >= str[oIndex]);
540 continue;
541 }
542 if (fChar[tIndex] != str[oIndex]) {
543 break;
544 }
545 ++tIndex;
546 ++oIndex;
547 }
548 return oIndex >= oLen;
549 }
550
Cary Clark8032b982017-07-28 11:04:54 -0400551 const char* strnchr(char ch, const char* end) const {
552 const char* ptr = fChar;
553 while (ptr < end) {
554 if (ptr[0] == ch) {
555 return ptr;
556 }
557 ++ptr;
558 }
559 return nullptr;
560 }
561
562 const char* strnstr(const char *match, const char* end) const {
563 size_t matchLen = strlen(match);
564 SkASSERT(matchLen > 0);
565 ptrdiff_t len = end - fChar;
566 SkASSERT(len >= 0);
567 if ((size_t) len < matchLen ) {
568 return nullptr;
569 }
570 size_t count = len - matchLen;
571 for (size_t index = 0; index <= count; index++) {
572 if (0 == strncmp(&fChar[index], match, matchLen)) {
573 return &fChar[index];
574 }
575 }
576 return nullptr;
577 }
578
Cary Clarkce101242017-09-01 15:51:02 -0400579 const char* trimmedBracketEnd(const char bracket) const {
580 int max = (int) (this->lineLength());
Cary Clark8032b982017-07-28 11:04:54 -0400581 int index = 0;
582 while (index < max && bracket != fChar[index]) {
583 ++index;
584 }
585 SkASSERT(index < max);
586 while (index > 0 && ' ' >= fChar[index - 1]) {
587 --index;
588 }
589 return fChar + index;
590 }
591
592 const char* trimmedLineEnd() const {
593 const char* result = this->lineEnd();
594 while (result > fChar && ' ' >= result[-1]) {
595 --result;
596 }
597 return result;
598 }
599
600 void trimEnd() {
601 while (fEnd > fStart && ' ' >= fEnd[-1]) {
602 --fEnd;
603 }
604 }
605
606 const char* wordEnd() const {
607 const char* end = fChar;
608 while (isalnum(end[0]) || '_' == end[0] || '-' == end[0]) {
609 ++end;
610 }
611 return end;
612 }
613
614 string fFileName;
615 const char* fStart;
616 const char* fLine;
617 const char* fChar;
618 const char* fEnd;
619 size_t fLineCount;
620};
621
622class EscapeParser : public TextParser {
623public:
624 EscapeParser(const char* start, const char* end) :
625 TextParser("", start, end, 0) {
626 const char* reader = fStart;
627 fStorage = new char[end - start];
628 char* writer = fStorage;
629 while (reader < fEnd) {
630 char ch = *reader++;
631 if (ch != '\\') {
632 *writer++ = ch;
633 } else {
634 char ctrl = *reader++;
635 if (ctrl == 'u') {
636 unsigned unicode = 0;
637 for (int i = 0; i < 4; ++i) {
638 unicode <<= 4;
639 SkASSERT((reader[0] >= '0' && reader[0] <= '9') ||
640 (reader[0] >= 'A' && reader[0] <= 'F'));
641 int nibble = *reader++ - '0';
642 if (nibble > 9) {
643 nibble = 'A'- '9' + 1;
644 }
645 unicode |= nibble;
646 }
647 SkASSERT(unicode < 256);
648 *writer++ = (unsigned char) unicode;
649 } else {
650 SkASSERT(ctrl == 'n');
651 *writer++ = '\n';
652 }
653 }
654 }
655 fStart = fLine = fChar = fStorage;
656 fEnd = writer;
657 }
658
659 virtual ~EscapeParser() {
660 delete fStorage;
661 }
662private:
663 char* fStorage;
664};
665
666class RootDefinition;
667
668class Definition : public NonAssignable {
669public:
670 enum Type {
671 kNone,
672 kWord,
673 kMark,
674 kKeyWord,
675 kBracket,
676 kPunctuation,
677 kFileType,
678 };
679
680 enum class TrimExtract {
681 kNo,
682 kYes
683 };
684
685 enum class MethodType {
686 kNone,
687 kConstructor,
688 kDestructor,
689 kOperator,
690 };
691
692 Definition() {}
693
Ben Wagner63fd7602017-10-09 15:45:33 -0400694 Definition(const char* start, const char* end, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400695 : fStart(start)
696 , fContentStart(start)
697 , fContentEnd(end)
698 , fParent(parent)
699 , fLineCount(line)
700 , fType(Type::kWord) {
701 if (parent) {
702 SkASSERT(parent->fFileName.length() > 0);
703 fFileName = parent->fFileName;
704 }
705 this->setParentIndex();
706 }
707
Ben Wagner63fd7602017-10-09 15:45:33 -0400708 Definition(MarkType markType, const char* start, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400709 : Definition(markType, start, nullptr, line, parent) {
710 }
711
Ben Wagner63fd7602017-10-09 15:45:33 -0400712 Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400713 : Definition(start, end, line, parent) {
714 fMarkType = markType;
Ben Wagner63fd7602017-10-09 15:45:33 -0400715 fType = Type::kMark;
Cary Clark8032b982017-07-28 11:04:54 -0400716 }
717
Ben Wagner63fd7602017-10-09 15:45:33 -0400718 Definition(Bracket bracket, const char* start, int lineCount, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400719 : Definition(start, nullptr, lineCount, parent) {
720 fBracket = bracket;
721 fType = Type::kBracket;
722 }
723
Ben Wagner63fd7602017-10-09 15:45:33 -0400724 Definition(KeyWord keyWord, const char* start, const char* end, int lineCount,
725 Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400726 : Definition(start, end, lineCount, parent) {
727 fKeyWord = keyWord;
728 fType = Type::kKeyWord;
729 }
730
Ben Wagner63fd7602017-10-09 15:45:33 -0400731 Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400732 : Definition(start, nullptr, lineCount, parent) {
733 fPunctuation = punctuation;
734 fType = Type::kPunctuation;
735 }
736
737 virtual ~Definition() {}
738
739 virtual RootDefinition* asRoot() { SkASSERT(0); return nullptr; }
740 virtual const RootDefinition* asRoot() const { SkASSERT(0); return nullptr; }
741
742 bool boilerplateIfDef(Definition* parent) {
743 const Definition& label = fTokens.front();
744 if (Type::kWord != label.fType) {
745 return false;
746 }
747 fName = string(label.fContentStart, label.fContentEnd - label.fContentStart);
748 return true;
749 }
750
751 // todo: this is matching #ifndef SkXXX_DEFINED for no particular reason
752 // it doesn't do anything useful with arbitrary input, e.g. #ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
753// also doesn't know what to do with SK_REQUIRE_LOCAL_VAR()
754 bool boilerplateDef(Definition* parent) {
755 if (!this->boilerplateIfDef(parent)) {
756 return false;
757 }
758 const char* s = fName.c_str();
759 const char* e = strchr(s, '_');
760 return true; // fixme: if this is trying to do something useful with define, do it here
761 if (!e) {
762 return false;
763 }
764 string prefix(s, e - s);
765 const char* inName = strstr(parent->fName.c_str(), prefix.c_str());
766 if (!inName) {
767 return false;
768 }
769 if ('/' != inName[-1] && '\\' != inName[-1]) {
770 return false;
771 }
772 if (strcmp(inName + prefix.size(), ".h")) {
773 return false;
774 }
775 return true;
776 }
777
778 bool boilerplateEndIf() {
779 return true;
780 }
781
782 bool checkMethod() const;
783
784 void setCanonicalFiddle();
Cary Clark73fa9722017-08-29 17:36:51 -0400785 bool crossCheck2(const Definition& includeToken) const;
Cary Clark8032b982017-07-28 11:04:54 -0400786 bool crossCheck(const Definition& includeToken) const;
787 bool crossCheckInside(const char* start, const char* end, const Definition& includeToken) const;
788 bool exampleToScript(string* result) const;
789
790 string extractText(TrimExtract trimExtract) const {
791 string result;
792 TextParser parser(fFileName, fContentStart, fContentEnd, fLineCount);
793 int childIndex = 0;
794 char mc = '#';
795 while (parser.fChar < parser.fEnd) {
796 if (TrimExtract::kYes == trimExtract && !parser.skipWhiteSpace()) {
797 break;
798 }
799 if (parser.next() == mc) {
800 if (parser.next() == mc) {
801 if (parser.next() == mc) {
802 mc = parser.next();
803 }
804 } else {
805 // fixme : more work to do if # style comment is in text
806 // if in method definition, could be alternate method name
807 --parser.fChar;
808 if (' ' < parser.fChar[0]) {
809 if (islower(parser.fChar[0])) {
810 result += '\n';
811 parser.skipLine();
812 } else {
813 SkASSERT(isupper(parser.fChar[0]));
814 parser.skipTo(fChildren[childIndex]->fTerminator);
815 if (mc == parser.fChar[0] && mc == parser.fChar[1]) {
816 parser.next();
817 parser.next();
818 }
819 childIndex++;
820 }
821 } else {
822 parser.skipLine();
823 }
824 continue;
825 }
826 } else {
827 --parser.fChar;
828 }
829 const char* end = parser.fEnd;
830 const char* mark = parser.strnchr(mc, end);
831 if (mark) {
832 end = mark;
833 }
834 string fragment(parser.fChar, end - parser.fChar);
835 trim_end(fragment);
836 if (TrimExtract::kYes == trimExtract) {
837 trim_start(fragment);
838 if (result.length()) {
839 result += '\n';
840 result += '\n';
841 }
842 }
843 if (TrimExtract::kYes == trimExtract || has_nonwhitespace(fragment)) {
844 result += fragment;
845 }
846 parser.skipTo(end);
847 }
848 return result;
849 }
850
851 string fiddleName() const;
852 string formatFunction() const;
853 const Definition* hasChild(MarkType markType) const;
854 const Definition* hasParam(const string& ref) const;
855 bool isClone() const { return fClone; }
856
857 Definition* iRootParent() {
858 Definition* test = fParent;
859 while (test) {
860 if (Type::kKeyWord == test->fType && KeyWord::kClass == test->fKeyWord) {
861 return test;
862 }
863 test = test->fParent;
864 }
865 return nullptr;
866 }
867
868 virtual bool isRoot() const { return false; }
869
870 int length() const {
871 return (int) (fContentEnd - fContentStart);
872 }
873
874 bool methodHasReturn(const string& name, TextParser* methodParser) const;
875 string methodName() const;
Ben Wagner63fd7602017-10-09 15:45:33 -0400876 bool nextMethodParam(TextParser* methodParser, const char** nextEndPtr,
Cary Clark8032b982017-07-28 11:04:54 -0400877 string* paramName) const;
878 bool paramsMatch(const string& fullRef, const string& name) const;
879
880 string printableName() const {
881 string result(fName);
882 std::replace(result.begin(), result.end(), '_', ' ');
883 return result;
884 }
885
Cary Clark9174bda2017-09-19 17:39:32 -0400886 template <typename T> T reportError(const char* errorStr) const {
887 TextParser tp(this);
888 tp.reportError(errorStr);
889 return T();
890 }
891
Cary Clark8032b982017-07-28 11:04:54 -0400892 virtual RootDefinition* rootParent() { SkASSERT(0); return nullptr; }
893
894 void setParentIndex() {
895 fParentIndex = fParent ? (int) fParent->fTokens.size() : -1;
896 }
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 size_t fLineCount = 0;
911 int fParentIndex = 0;
912 MarkType fMarkType = MarkType::kNone;
913 KeyWord fKeyWord = KeyWord::kNone;
914 Bracket fBracket = Bracket::kNone;
915 Punctuation fPunctuation = Punctuation::kNone;
916 MethodType fMethodType = MethodType::kNone;
917 Type fType = Type::kNone;
918 bool fClone = false;
919 bool fCloned = false;
920 bool fPrivate = false;
921 bool fShort = false;
922 bool fMemberStart = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -0400923 bool fAnonymous = false;
Cary Clark8032b982017-07-28 11:04:54 -0400924 mutable bool fVisited = false;
925};
926
927class RootDefinition : public Definition {
928public:
Cary Clarkce101242017-09-01 15:51:02 -0400929 enum class AllowParens {
930 kNo,
931 kYes,
932 };
933
Cary Clark8032b982017-07-28 11:04:54 -0400934 RootDefinition() {
935 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400936
Cary Clark8032b982017-07-28 11:04:54 -0400937 RootDefinition(MarkType markType, const char* start, int line, Definition* parent)
938 : Definition(markType, start, line, parent) {
939 }
940
Ben Wagner63fd7602017-10-09 15:45:33 -0400941 RootDefinition(MarkType markType, const char* start, const char* end, int line,
Cary Clark8032b982017-07-28 11:04:54 -0400942 Definition* parent) : Definition(markType, start, end, line, parent) {
943 }
944
945 ~RootDefinition() override {
946 for (auto& iter : fBranches) {
947 delete iter.second;
948 }
949 }
950
951 RootDefinition* asRoot() override { return this; }
952 const RootDefinition* asRoot() const override { return this; }
953 void clearVisited();
954 bool dumpUnVisited();
Cary Clarkce101242017-09-01 15:51:02 -0400955 const Definition* find(const string& ref, AllowParens ) const;
Cary Clark8032b982017-07-28 11:04:54 -0400956 bool isRoot() const override { return true; }
957 RootDefinition* rootParent() override { return fRootParent; }
958 void setRootParent(RootDefinition* rootParent) { fRootParent = rootParent; }
959
960 unordered_map<string, RootDefinition*> fBranches;
961 unordered_map<string, Definition> fLeaves;
962private:
963 RootDefinition* fRootParent = nullptr;
964};
965
966struct IClassDefinition : public Definition {
967 unordered_map<string, Definition*> fEnums;
968 unordered_map<string, Definition*> fMembers;
969 unordered_map<string, Definition*> fMethods;
970 unordered_map<string, Definition*> fStructs;
971};
972
973struct Reference {
974 Reference()
975 : fLocation(nullptr)
976 , fDefinition(nullptr) {
977 }
978
979 const char* fLocation; // .. in original text file
980 const Definition* fDefinition;
981};
982
983struct TypeNames {
984 const char* fName;
985 MarkType fMarkType;
986};
987
988class ParserCommon : public TextParser {
989public:
990
991 ParserCommon() : TextParser()
992 , fParent(nullptr)
Cary Clarkd0530ba2017-09-14 11:25:39 -0400993 , fDebugOut(false)
Cary Clark8032b982017-07-28 11:04:54 -0400994 {
995 }
996
997 virtual ~ParserCommon() {
998 }
999
1000 void addDefinition(Definition* def) {
1001 fParent->fChildren.push_back(def);
1002 fParent = def;
1003 }
1004
1005 void indentToColumn(int column) {
1006 SkASSERT(column >= fColumn);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001007 if (fDebugOut) {
1008 SkDebugf("%*s", column - fColumn, "");
1009 }
Cary Clark8032b982017-07-28 11:04:54 -04001010 fprintf(fOut, "%*s", column - fColumn, "");
1011 fColumn = column;
1012 fSpaces += column - fColumn;
1013 }
1014
1015 bool leadingPunctuation(const char* str, size_t len) const {
1016 if (!fPendingSpace) {
1017 return false;
1018 }
1019 if (len < 2) {
1020 return false;
1021 }
1022 if ('.' != str[0] && ',' != str[0] && ';' != str[0] && ':' != str[0]) {
1023 return false;
1024 }
1025 return ' ' >= str[1];
1026 }
1027
1028 void lf(int count) {
1029 fPendingLF = SkTMax(fPendingLF, count);
1030 this->nl();
1031 }
1032
1033 void lfAlways(int count) {
1034 this->lf(count);
1035 this->writePending();
1036 }
1037
1038 void lfcr() {
1039 this->lf(1);
1040 }
1041
1042 void nl() {
1043 fLinefeeds = 0;
1044 fSpaces = 0;
1045 fColumn = 0;
Cary Clark9174bda2017-09-19 17:39:32 -04001046 fPendingSpace = 0;
Cary Clark8032b982017-07-28 11:04:54 -04001047 }
1048
1049 bool parseFile(const char* file, const char* suffix);
1050 virtual bool parseFromFile(const char* path) = 0;
1051 bool parseSetup(const char* path);
1052
1053 void popObject() {
1054 fParent->fContentEnd = fParent->fTerminator = fChar;
1055 fParent = fParent->fParent;
1056 }
1057
1058 virtual void reset() = 0;
1059
1060 void resetCommon() {
1061 fLine = fChar = fStart;
1062 fLineCount = 0;
1063 fParent = nullptr;
1064 fIndent = 0;
1065 fOut = nullptr;
1066 fMaxLF = 2;
1067 fPendingLF = 0;
Cary Clark9174bda2017-09-19 17:39:32 -04001068 fPendingSpace = 0;
Cary Clark154beea2017-10-26 07:58:48 -04001069 fOutdentNext = false;
Cary Clark8032b982017-07-28 11:04:54 -04001070 nl();
1071 }
1072
1073 void setAsParent(Definition* definition) {
1074 if (fParent) {
1075 fParent->fChildren.push_back(definition);
1076 definition->fParent = fParent;
1077 }
1078 fParent = definition;
1079 }
1080
1081 void singleLF() {
1082 fMaxLF = 1;
1083 }
1084
Cary Clark8032b982017-07-28 11:04:54 -04001085
1086 void writeBlock(int size, const char* data) {
1087 SkAssertResult(writeBlockTrim(size, data));
1088 }
Cary Clark154beea2017-10-26 07:58:48 -04001089
1090 void writeBlockIndent(int size, const char* data);
1091 bool writeBlockTrim(int size, const char* data);
1092
Cary Clark8032b982017-07-28 11:04:54 -04001093 void writeCommentHeader() {
1094 this->lf(2);
1095 this->writeString("/**");
1096 this->writeSpace();
1097 }
1098
1099 void writeCommentTrailer() {
1100 this->writeString("*/");
1101 this->lfcr();
1102 }
1103
Cary Clark154beea2017-10-26 07:58:48 -04001104 void writePending();
1105
Cary Clark8032b982017-07-28 11:04:54 -04001106 // write a pending space, so that two consecutive calls
1107 // don't double write, and trailing spaces on lines aren't written
Cary Clark9174bda2017-09-19 17:39:32 -04001108 void writeSpace(int count = 1) {
Cary Clark8032b982017-07-28 11:04:54 -04001109 SkASSERT(!fPendingLF);
1110 SkASSERT(!fLinefeeds);
1111 SkASSERT(fColumn > 0);
1112 SkASSERT(!fSpaces);
Cary Clark9174bda2017-09-19 17:39:32 -04001113 fPendingSpace = count;
Cary Clark8032b982017-07-28 11:04:54 -04001114 }
1115
Cary Clark154beea2017-10-26 07:58:48 -04001116 void writeString(const char* str);
Cary Clark8032b982017-07-28 11:04:54 -04001117
Cary Clark9174bda2017-09-19 17:39:32 -04001118 void writeString(const string& str) {
1119 this->writeString(str.c_str());
1120 }
1121
Cary Clark8032b982017-07-28 11:04:54 -04001122
1123 unordered_map<string, sk_sp<SkData>> fRawData;
1124 unordered_map<string, vector<char>> fLFOnly;
1125 Definition* fParent;
1126 FILE* fOut;
1127 int fLinefeeds; // number of linefeeds last written, zeroed on non-space
Cary Clark9174bda2017-09-19 17:39:32 -04001128 int fMaxLF; // number of linefeeds allowed
1129 int fPendingLF; // number of linefeeds to write (can be suppressed)
1130 int fSpaces; // number of spaces (indent) last written, zeroed on non-space
1131 int fColumn; // current column; number of chars past last linefeed
1132 int fIndent; // desired indention
1133 int fPendingSpace; // one or two spaces should preceed the next string or block
1134 char fLastChar; // last written
1135 bool fDebugOut; // set true to write to std out
Cary Clark154beea2017-10-26 07:58:48 -04001136 bool fOutdentNext; // set at end of embedded struct to prevent premature outdent
Cary Clark8032b982017-07-28 11:04:54 -04001137private:
1138 typedef TextParser INHERITED;
1139};
1140
1141
1142
1143class BmhParser : public ParserCommon {
1144public:
1145 enum class MarkLookup {
1146 kRequire,
1147 kAllowUnknown,
1148 };
1149
1150 enum class Resolvable {
1151 kNo, // neither resolved nor output
1152 kYes, // resolved, output
1153 kOut, // not resolved, but output
Cary Clark154beea2017-10-26 07:58:48 -04001154 kLiteral, // output untouched (FIXME: is this really different from kOut?)
Cary Clark8032b982017-07-28 11:04:54 -04001155 };
1156
1157 enum class Exemplary {
1158 kNo,
1159 kYes,
1160 kOptional,
1161 };
1162
Cary Clarkce101242017-09-01 15:51:02 -04001163 enum class TableState {
1164 kNone,
1165 kColumnStart,
1166 kColumnEnd,
1167 };
1168
Cary Clark8032b982017-07-28 11:04:54 -04001169#define M(mt) (1LL << (int) MarkType::k##mt)
1170#define M_D M(Description)
1171#define M_CS M(Class) | M(Struct)
1172#define M_ST M(Subtopic) | M(Topic)
1173#define M_CSST M_CS | M_ST
1174#ifdef M_E
1175#undef M_E
1176#endif
1177#define M_E M(Enum) | M(EnumClass)
1178
1179#define R_Y Resolvable::kYes
1180#define R_N Resolvable::kNo
1181#define R_O Resolvable::kOut
1182
1183#define E_Y Exemplary::kYes
1184#define E_N Exemplary::kNo
1185#define E_O Exemplary::kOptional
1186
1187 BmhParser() : ParserCommon()
Ben Wagner63fd7602017-10-09 15:45:33 -04001188 , fMaps {
Cary Clark8032b982017-07-28 11:04:54 -04001189// names without formal definitions (e.g. Column) aren't included
1190// fill in other names once they're actually used
Cary Clarkce101242017-09-01 15:51:02 -04001191 { "", nullptr, MarkType::kNone, R_Y, E_N, 0 }
1192, { "A", nullptr, MarkType::kAnchor, R_Y, E_N, 0 }
1193, { "Alias", nullptr, MarkType::kAlias, R_N, E_N, 0 }
1194, { "Bug", nullptr, MarkType::kBug, R_N, E_N, 0 }
1195, { "Class", &fClassMap, MarkType::kClass, R_Y, E_O, M_CSST | M(Root) }
Cary Clark154beea2017-10-26 07:58:48 -04001196, { "Code", nullptr, MarkType::kCode, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clarkce101242017-09-01 15:51:02 -04001197, { "", nullptr, MarkType::kColumn, R_Y, E_N, M(Row) }
1198, { "", nullptr, MarkType::kComment, R_N, E_N, 0 }
1199, { "Const", &fConstMap, MarkType::kConst, R_Y, E_N, M_E | M_ST }
1200, { "Define", nullptr, MarkType::kDefine, R_O, E_N, M_ST }
1201, { "DefinedBy", nullptr, MarkType::kDefinedBy, R_N, E_N, M(Method) }
1202, { "Deprecated", nullptr, MarkType::kDeprecated, R_Y, E_N, 0 }
1203, { "Description", nullptr, MarkType::kDescription, R_Y, E_N, M(Example) }
1204, { "Doxygen", nullptr, MarkType::kDoxygen, R_Y, E_N, 0 }
1205, { "Enum", &fEnumMap, MarkType::kEnum, R_Y, E_O, M_CSST | M(Root) }
1206, { "EnumClass", &fClassMap, MarkType::kEnumClass, R_Y, E_O, M_CSST | M(Root) }
1207, { "Error", nullptr, MarkType::kError, R_N, E_N, M(Example) }
1208, { "Example", nullptr, MarkType::kExample, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clarkbad5ad72017-08-03 17:14:08 -04001209, { "Experimental", nullptr, MarkType::kExperimental, R_Y, E_N, 0 }
Cary Clarkce101242017-09-01 15:51:02 -04001210, { "External", nullptr, MarkType::kExternal, R_Y, E_N, M(Root) }
1211, { "File", nullptr, MarkType::kFile, R_N, E_N, M(Track) }
Ben Wagner63fd7602017-10-09 15:45:33 -04001212, { "Formula", nullptr, MarkType::kFormula, R_O, E_N,
Cary Clarkce101242017-09-01 15:51:02 -04001213 M(Column) | M_ST | M(Member) | M(Method) | M_D }
1214, { "Function", nullptr, MarkType::kFunction, R_O, E_N, M(Example) }
1215, { "Height", nullptr, MarkType::kHeight, R_N, E_N, M(Example) }
1216, { "Image", nullptr, MarkType::kImage, R_N, E_N, M(Example) }
1217, { "Legend", nullptr, MarkType::kLegend, R_Y, E_N, M(Table) }
1218, { "", nullptr, MarkType::kLink, R_N, E_N, M(Anchor) }
1219, { "List", nullptr, MarkType::kList, R_Y, E_N, M(Method) | M_CSST | M_E | M_D }
Cary Clark154beea2017-10-26 07:58:48 -04001220, { "Literal", nullptr, MarkType::kLiteral, R_N, E_N, M(Code) }
Cary Clarkce101242017-09-01 15:51:02 -04001221, { "", nullptr, MarkType::kMarkChar, R_N, E_N, 0 }
1222, { "Member", nullptr, MarkType::kMember, R_Y, E_N, M(Class) | M(Struct) }
1223, { "Method", &fMethodMap, MarkType::kMethod, R_Y, E_Y, M_CSST }
1224, { "NoExample", nullptr, MarkType::kNoExample, R_Y, E_N, 0 }
Cary Clark154beea2017-10-26 07:58:48 -04001225, { "Outdent", nullptr, MarkType::kOutdent, R_N, E_N, M(Code) }
Cary Clarkce101242017-09-01 15:51:02 -04001226, { "Param", nullptr, MarkType::kParam, R_Y, E_N, M(Method) }
1227, { "Platform", nullptr, MarkType::kPlatform, R_N, E_N, M(Example) }
1228, { "Private", nullptr, MarkType::kPrivate, R_N, E_N, 0 }
1229, { "Return", nullptr, MarkType::kReturn, R_Y, E_N, M(Method) }
1230, { "", nullptr, MarkType::kRoot, R_Y, E_N, 0 }
1231, { "", nullptr, MarkType::kRow, R_Y, E_N, M(Table) | M(List) }
1232, { "SeeAlso", nullptr, MarkType::kSeeAlso, R_Y, E_N, M_CSST | M_E | M(Method) }
1233, { "StdOut", nullptr, MarkType::kStdOut, R_N, E_N, M(Example) }
1234, { "Struct", &fClassMap, MarkType::kStruct, R_Y, E_O, M(Class) | M(Root) | M_ST }
1235, { "Substitute", nullptr, MarkType::kSubstitute, R_N, E_N, M_ST }
1236, { "Subtopic", nullptr, MarkType::kSubtopic, R_Y, E_Y, M_CSST }
1237, { "Table", nullptr, MarkType::kTable, R_Y, E_N, M(Method) | M_CSST | M_E }
1238, { "Template", nullptr, MarkType::kTemplate, R_Y, E_N, 0 }
1239, { "", nullptr, MarkType::kText, R_Y, E_N, 0 }
1240, { "Time", nullptr, MarkType::kTime, R_Y, E_N, M(Track) }
1241, { "ToDo", nullptr, MarkType::kToDo, R_N, E_N, 0 }
1242, { "Topic", nullptr, MarkType::kTopic, R_Y, E_Y, M_CS | M(Root) | M(Topic) }
1243, { "Track", nullptr, MarkType::kTrack, R_Y, E_N, M_E | M_ST }
1244, { "Typedef", &fTypedefMap, MarkType::kTypedef, R_Y, E_N, M(Subtopic) | M(Topic) }
1245, { "", nullptr, MarkType::kUnion, R_Y, E_N, 0 }
1246, { "Volatile", nullptr, MarkType::kVolatile, R_N, E_N, M(StdOut) }
1247, { "Width", nullptr, MarkType::kWidth, R_N, E_N, M(Example) } }
Cary Clark8032b982017-07-28 11:04:54 -04001248 {
1249 this->reset();
1250 }
1251
1252#undef R_O
1253#undef R_N
1254#undef R_Y
1255
1256#undef M_E
1257#undef M_CSST
1258#undef M_ST
1259#undef M_CS
1260#undef M_D
1261#undef M
1262
1263 ~BmhParser() override {}
1264
1265 bool addDefinition(const char* defStart, bool hasEnd, MarkType markType,
1266 const vector<string>& typeNameBuilder);
Cary Clark73fa9722017-08-29 17:36:51 -04001267 bool checkExamples() const;
Cary Clarka523d2d2017-08-30 08:58:10 -04001268 bool checkParamReturn(const Definition* definition) const;
Cary Clark73fa9722017-08-29 17:36:51 -04001269 bool dumpExamples(const char* fiddleJsonFileName) const;
Cary Clark8032b982017-07-28 11:04:54 -04001270 bool childOf(MarkType markType) const;
1271 string className(MarkType markType);
1272 bool collectExternals();
1273 int endHashCount() const;
Cary Clarkce101242017-09-01 15:51:02 -04001274 bool endTableColumn(const char* end, const char* terminator);
Cary Clark8032b982017-07-28 11:04:54 -04001275
1276 RootDefinition* findBmhObject(MarkType markType, const string& typeName) {
1277 auto map = fMaps[(int) markType].fBmh;
1278 if (!map) {
1279 return nullptr;
1280 }
1281 return &(*map)[typeName];
1282 }
1283
1284 bool findDefinitions();
1285 MarkType getMarkType(MarkLookup lookup) const;
1286 bool hasEndToken() const;
1287 string memberName();
1288 string methodName();
1289 const Definition* parentSpace() const;
1290
1291 bool parseFromFile(const char* path) override {
1292 if (!INHERITED::parseSetup(path)) {
1293 return false;
1294 }
1295 fCheckMethods = !strstr(path, "undocumented.bmh");
1296 return findDefinitions();
1297 }
1298
1299 bool popParentStack(Definition* definition);
Cary Clark73fa9722017-08-29 17:36:51 -04001300 void reportDuplicates(const Definition& def, const string& dup) const;
Cary Clark8032b982017-07-28 11:04:54 -04001301
1302 void reset() override {
1303 INHERITED::resetCommon();
1304 fRoot = nullptr;
Cary Clarkce101242017-09-01 15:51:02 -04001305 fWorkingColumn = nullptr;
1306 fRow = nullptr;
1307 fTableState = TableState::kNone;
Cary Clark8032b982017-07-28 11:04:54 -04001308 fMC = '#';
1309 fInChar = false;
1310 fInCharCommentString = false;
1311 fInComment = false;
1312 fInEnum = false;
1313 fInString = false;
1314 fCheckMethods = false;
1315 }
1316
1317 bool skipNoName();
1318 bool skipToDefinitionEnd(MarkType markType);
Cary Clarkce101242017-09-01 15:51:02 -04001319 void spellCheck(const char* match, SkCommandLineFlags::StringArray report) const;
Cary Clark8032b982017-07-28 11:04:54 -04001320 vector<string> topicName();
1321 vector<string> typeName(MarkType markType, bool* expectEnd);
1322 string uniqueName(const string& base, MarkType markType);
1323 string uniqueRootName(const string& base, MarkType markType);
1324 void validate() const;
1325 string word(const string& prefix, const string& delimiter);
1326
1327public:
1328 struct DefinitionMap {
1329 const char* fName;
1330 unordered_map<string, RootDefinition>* fBmh;
1331 MarkType fMarkType;
1332 Resolvable fResolve;
1333 Exemplary fExemplary; // worthy of an example
1334 uint64_t fParentMask;
1335 };
Ben Wagner63fd7602017-10-09 15:45:33 -04001336
Cary Clark8032b982017-07-28 11:04:54 -04001337 DefinitionMap fMaps[Last_MarkType + 1];
1338 forward_list<RootDefinition> fTopics;
1339 forward_list<Definition> fMarkup;
1340 forward_list<RootDefinition> fExternals;
1341 vector<string> fInputFiles;
1342 unordered_map<string, RootDefinition> fClassMap;
1343 unordered_map<string, RootDefinition> fConstMap;
1344 unordered_map<string, RootDefinition> fEnumMap;
1345 unordered_map<string, RootDefinition> fMethodMap;
1346 unordered_map<string, RootDefinition> fTypedefMap;
1347 unordered_map<string, Definition*> fTopicMap;
1348 unordered_map<string, Definition*> fAliasMap;
1349 RootDefinition* fRoot;
Cary Clarkce101242017-09-01 15:51:02 -04001350 Definition* fWorkingColumn;
1351 Definition* fRow;
1352 const char* fColStart;
1353 TableState fTableState;
Cary Clark8032b982017-07-28 11:04:54 -04001354 mutable char fMC; // markup character
1355 bool fAnonymous;
1356 bool fCloned;
1357 bool fInChar;
1358 bool fInCharCommentString;
1359 bool fInEnum;
1360 bool fInComment;
1361 bool fInString;
1362 bool fCheckMethods;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001363 bool fWroteOut = false;
Cary Clark8032b982017-07-28 11:04:54 -04001364private:
1365 typedef ParserCommon INHERITED;
1366};
1367
1368class IncludeParser : public ParserCommon {
1369public:
1370 enum class IsStruct {
1371 kNo,
1372 kYes,
1373 };
1374
1375 IncludeParser() : ParserCommon()
1376 , fMaps {
1377 { nullptr, MarkType::kNone }
1378 , { nullptr, MarkType::kAnchor }
1379 , { nullptr, MarkType::kAlias }
1380 , { nullptr, MarkType::kBug }
1381 , { nullptr, MarkType::kClass }
1382 , { nullptr, MarkType::kCode }
1383 , { nullptr, MarkType::kColumn }
1384 , { nullptr, MarkType::kComment }
1385 , { nullptr, MarkType::kConst }
1386 , { &fIDefineMap, MarkType::kDefine }
1387 , { nullptr, MarkType::kDefinedBy }
1388 , { nullptr, MarkType::kDeprecated }
1389 , { nullptr, MarkType::kDescription }
1390 , { nullptr, MarkType::kDoxygen }
1391 , { &fIEnumMap, MarkType::kEnum }
1392 , { &fIEnumMap, MarkType::kEnumClass }
1393 , { nullptr, MarkType::kError }
1394 , { nullptr, MarkType::kExample }
1395 , { nullptr, MarkType::kExperimental }
1396 , { nullptr, MarkType::kExternal }
1397 , { nullptr, MarkType::kFile }
1398 , { nullptr, MarkType::kFormula }
1399 , { nullptr, MarkType::kFunction }
1400 , { nullptr, MarkType::kHeight }
1401 , { nullptr, MarkType::kImage }
1402 , { nullptr, MarkType::kLegend }
1403 , { nullptr, MarkType::kLink }
1404 , { nullptr, MarkType::kList }
Cary Clark154beea2017-10-26 07:58:48 -04001405 , { nullptr, MarkType::kLiteral }
Cary Clark8032b982017-07-28 11:04:54 -04001406 , { nullptr, MarkType::kMarkChar }
1407 , { nullptr, MarkType::kMember }
1408 , { nullptr, MarkType::kMethod }
1409 , { nullptr, MarkType::kNoExample }
Cary Clark154beea2017-10-26 07:58:48 -04001410 , { nullptr, MarkType::kOutdent }
Cary Clark8032b982017-07-28 11:04:54 -04001411 , { nullptr, MarkType::kParam }
1412 , { nullptr, MarkType::kPlatform }
1413 , { nullptr, MarkType::kPrivate }
1414 , { nullptr, MarkType::kReturn }
1415 , { nullptr, MarkType::kRoot }
1416 , { nullptr, MarkType::kRow }
1417 , { nullptr, MarkType::kSeeAlso }
1418 , { nullptr, MarkType::kStdOut }
1419 , { &fIStructMap, MarkType::kStruct }
1420 , { nullptr, MarkType::kSubstitute }
1421 , { nullptr, MarkType::kSubtopic }
1422 , { nullptr, MarkType::kTable }
1423 , { &fITemplateMap, MarkType::kTemplate }
1424 , { nullptr, MarkType::kText }
1425 , { nullptr, MarkType::kTime }
1426 , { nullptr, MarkType::kToDo }
1427 , { nullptr, MarkType::kTopic }
1428 , { nullptr, MarkType::kTrack }
1429 , { &fITypedefMap, MarkType::kTypedef }
1430 , { &fIUnionMap, MarkType::kUnion }
1431 , { nullptr, MarkType::kVolatile }
1432 , { nullptr, MarkType::kWidth } }
1433 {
1434 this->reset();
1435 }
1436
1437 ~IncludeParser() override {}
1438
1439 void addKeyword(KeyWord keyWord);
1440
1441 void addPunctuation(Punctuation punctuation) {
1442 fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent);
1443 }
1444
1445 void addWord() {
1446 fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent);
1447 fIncludeWord = nullptr;
1448 }
1449
1450 void checkForMissingParams(const vector<string>& methodParams,
1451 const vector<string>& foundParams);
1452 bool checkForWord();
1453 string className() const;
1454 bool crossCheck(BmhParser& );
1455 IClassDefinition* defineClass(const Definition& includeDef, const string& className);
1456 void dumpClassTokens(IClassDefinition& classDef);
Cary Clark9174bda2017-09-19 17:39:32 -04001457 void dumpComment(const Definition& );
1458 void dumpEnum(const Definition& );
1459 void dumpMethod(const Definition& );
1460 void dumpMember(const Definition& );
Cary Clarkd0530ba2017-09-14 11:25:39 -04001461 bool dumpTokens(const string& directory);
Cary Clark9174bda2017-09-19 17:39:32 -04001462 bool dumpTokens(const string& directory, const string& skClassName);
Cary Clark8032b982017-07-28 11:04:54 -04001463 bool findComments(const Definition& includeDef, Definition* markupDef);
1464
1465 Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
1466 const string& typeName) {
1467 typedef Definition* DefinitionPtr;
1468 unordered_map<string, Definition>* map = fMaps[(int) markType].fInclude;
1469 if (!map) {
1470 return reportError<DefinitionPtr>("invalid mark type");
1471 }
1472 string name = this->uniqueName(*map, typeName);
1473 Definition& markupDef = (*map)[name];
1474 if (markupDef.fStart) {
1475 return reportError<DefinitionPtr>("definition already defined");
1476 }
1477 markupDef.fFileName = fFileName;
1478 markupDef.fStart = includeDef.fStart;
1479 markupDef.fContentStart = includeDef.fStart;
1480 markupDef.fName = name;
1481 markupDef.fContentEnd = includeDef.fContentEnd;
1482 markupDef.fTerminator = includeDef.fTerminator;
1483 markupDef.fParent = fParent;
1484 markupDef.fLineCount = includeDef.fLineCount;
1485 markupDef.fMarkType = markType;
1486 markupDef.fKeyWord = includeDef.fKeyWord;
1487 markupDef.fType = Definition::Type::kMark;
1488 return &markupDef;
1489 }
1490
1491 static KeyWord FindKey(const char* start, const char* end);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001492 bool internalName(const Definition& ) const;
Cary Clark8032b982017-07-28 11:04:54 -04001493 bool parseChar();
1494 bool parseComment(const string& filename, const char* start, const char* end, int lineCount,
1495 Definition* markupDef);
1496 bool parseClass(Definition* def, IsStruct);
1497 bool parseDefine();
1498 bool parseEnum(Definition* child, Definition* markupDef);
1499
1500 bool parseFromFile(const char* path) override {
1501 if (!INHERITED::parseSetup(path)) {
1502 return false;
1503 }
1504 string name(path);
1505 return parseInclude(name);
1506 }
1507
1508 bool parseInclude(const string& name);
1509 bool parseMember(Definition* child, Definition* markupDef);
1510 bool parseMethod(Definition* child, Definition* markupDef);
1511 bool parseObject(Definition* child, Definition* markupDef);
1512 bool parseObjects(Definition* parent, Definition* markupDef);
1513 bool parseTemplate();
1514 bool parseTypedef();
1515 bool parseUnion();
1516
1517 void popBracket() {
1518 SkASSERT(Definition::Type::kBracket == fParent->fType);
1519 this->popObject();
1520 Bracket bracket = this->topBracket();
1521 this->setBracketShortCuts(bracket);
1522 }
1523
1524 void pushBracket(Bracket bracket) {
1525 this->setBracketShortCuts(bracket);
1526 fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent);
1527 Definition* container = &fParent->fTokens.back();
1528 this->addDefinition(container);
1529 }
1530
1531 void reset() override {
1532 INHERITED::resetCommon();
1533 fRootTopic = nullptr;
1534 fInBrace = nullptr;
1535 fIncludeWord = nullptr;
Cary Clark73fa9722017-08-29 17:36:51 -04001536 fLastObject = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001537 fPrev = '\0';
1538 fInChar = false;
1539 fInCharCommentString = false;
1540 fInComment = false;
1541 fInEnum = false;
1542 fInFunction = false;
1543 fInString = false;
1544 }
1545
1546 void setBracketShortCuts(Bracket bracket) {
1547 fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket;
1548 fInString = Bracket::kString == bracket;
1549 fInChar = Bracket::kChar == bracket;
1550 fInCharCommentString = fInChar || fInComment || fInString;
1551 }
1552
1553 Bracket topBracket() const {
1554 Definition* parent = fParent;
1555 while (parent && Definition::Type::kBracket != parent->fType) {
1556 parent = parent->fParent;
1557 }
1558 return parent ? parent->fBracket : Bracket::kNone;
1559 }
1560
1561 template <typename T>
1562 string uniqueName(const unordered_map<string, T>& m, const string& typeName) {
1563 string base(typeName.size() > 0 ? typeName : "_anonymous");
1564 string name(base);
1565 int anonCount = 1;
1566 do {
1567 auto iter = m.find(name);
1568 if (iter == m.end()) {
1569 return name;
1570 }
1571 name = base + '_';
1572 name += to_string(++anonCount);
1573 } while (true);
1574 // should never get here
1575 return string();
1576 }
1577
1578 void validate() const;
1579
Cary Clark9174bda2017-09-19 17:39:32 -04001580 void writeDefinition(const Definition& def) {
1581 if (def.length() > 1) {
1582 this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1583 this->lf(1);
1584 }
1585 }
1586
1587 void writeDefinition(const Definition& def, const string& name, int spaces) {
1588 this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1589 this->writeSpace(spaces);
1590 this->writeString(name);
1591 this->lf(1);
1592 }
1593
1594 void writeEndTag() {
1595 this->lf(1);
1596 this->writeString("##");
1597 this->lf(1);
1598 }
1599
1600 void writeEndTag(const char* tagType) {
1601 this->lf(1);
1602 this->writeString(string("#") + tagType + " ##");
1603 this->lf(1);
1604 }
1605
1606 void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) {
1607 this->lf(1);
1608 this->writeString(string("#") + tagType + " " + tagID);
1609 this->writeSpace(spaces);
1610 this->writeString("##");
1611 this->lf(1);
1612 }
1613
1614 void writeEndTag(const char* tagType, const string& tagID, int spaces = 1) {
1615 this->writeEndTag(tagType, tagID.c_str(), spaces);
1616 }
1617
Cary Clark154beea2017-10-26 07:58:48 -04001618 void writeIncompleteTag(const char* tagType, const string& tagID, int spaces = 1) {
1619 this->writeString(string("#") + tagType + " " + tagID);
1620 this->writeSpace(spaces);
1621 this->writeString("incomplete");
1622 this->writeSpace();
1623 this->writeString("##");
1624 this->lf(1);
1625 }
1626
1627 void writeIncompleteTag(const char* tagType) {
1628 this->writeString(string("#") + tagType + " incomplete ##");
1629 this->lf(1);
1630 }
1631
Cary Clark9174bda2017-09-19 17:39:32 -04001632 void writeTableHeader(const char* col1, size_t pad, const char* col2) {
1633 this->lf(1);
1634 this->writeString("#Table");
1635 this->lf(1);
1636 this->writeString("#Legend");
1637 this->lf(1);
1638 string legend = "# ";
1639 legend += col1;
1640 if (pad > strlen(col1)) {
1641 legend += string(pad - strlen(col1), ' ');
1642 }
1643 legend += " # ";
1644 legend += col2;
1645 legend += " ##";
1646 this->writeString(legend);
1647 this->lf(1);
1648 this->writeString("#Legend ##");
1649 this->lf(1);
1650 }
1651
1652 void writeTableRow(size_t pad, const string& col1) {
1653 this->lf(1);
1654 string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##";
1655 this->writeString(row);
1656 this->lf(1);
1657 }
1658
1659 void writeTableTrailer() {
1660 this->lf(1);
1661 this->writeString("#Table ##");
1662 this->lf(1);
1663 }
1664
1665 void writeTag(const char* tagType) {
1666 this->lf(1);
1667 this->writeString("#");
1668 this->writeString(tagType);
1669 }
1670
1671 void writeTagNoLF(const char* tagType, const char* tagID) {
1672 this->writeString("#");
1673 this->writeString(tagType);
1674 this->writeSpace();
1675 this->writeString(tagID);
1676 }
1677
1678 void writeTagNoLF(const char* tagType, const string& tagID) {
1679 this->writeTagNoLF(tagType, tagID.c_str());
1680 }
1681
1682 void writeTag(const char* tagType, const char* tagID) {
1683 this->lf(1);
1684 this->writeTagNoLF(tagType, tagID);
1685 }
1686
1687 void writeTag(const char* tagType, const string& tagID) {
1688 this->writeTag(tagType, tagID.c_str());
1689 }
1690
Cary Clark8032b982017-07-28 11:04:54 -04001691protected:
1692 static void ValidateKeyWords();
1693
1694 struct DefinitionMap {
1695 unordered_map<string, Definition>* fInclude;
1696 MarkType fMarkType;
1697 };
Ben Wagner63fd7602017-10-09 15:45:33 -04001698
Cary Clark8032b982017-07-28 11:04:54 -04001699 DefinitionMap fMaps[Last_MarkType + 1];
1700 unordered_map<string, Definition> fIncludeMap;
1701 unordered_map<string, IClassDefinition> fIClassMap;
1702 unordered_map<string, Definition> fIDefineMap;
1703 unordered_map<string, Definition> fIEnumMap;
1704 unordered_map<string, Definition> fIStructMap;
1705 unordered_map<string, Definition> fITemplateMap;
1706 unordered_map<string, Definition> fITypedefMap;
1707 unordered_map<string, Definition> fIUnionMap;
1708 Definition* fRootTopic;
1709 Definition* fInBrace;
Cary Clark73fa9722017-08-29 17:36:51 -04001710 Definition* fLastObject;
Cary Clark8032b982017-07-28 11:04:54 -04001711 const char* fIncludeWord;
1712 char fPrev;
1713 bool fInChar;
1714 bool fInCharCommentString;
1715 bool fInComment;
1716 bool fInEnum;
1717 bool fInFunction;
1718 bool fInString;
1719
1720 typedef ParserCommon INHERITED;
1721};
1722
1723class IncludeWriter : public IncludeParser {
1724public:
1725 enum class Word {
1726 kStart,
1727 kCap,
1728 kFirst,
1729 kUnderline,
1730 kMixed,
1731 };
1732
Cary Clarkd0530ba2017-09-14 11:25:39 -04001733 enum class Phrase {
1734 kNo,
1735 kYes,
1736 };
1737
Cary Clark8032b982017-07-28 11:04:54 -04001738 enum class PunctuationState {
1739 kStart,
1740 kDelimiter,
1741 kPeriod,
Cary Clark1eace2d2017-07-31 07:52:43 -04001742 kSpace,
Cary Clark8032b982017-07-28 11:04:54 -04001743 };
1744
Cary Clarkce101242017-09-01 15:51:02 -04001745 enum class RefType {
1746 kUndefined,
1747 kNormal,
1748 kExternal,
1749 };
1750
Cary Clark8032b982017-07-28 11:04:54 -04001751 enum class Wrote {
1752 kNone,
1753 kLF,
1754 kChars,
1755 };
1756
Cary Clarkbad5ad72017-08-03 17:14:08 -04001757 struct IterState {
Ben Wagner63fd7602017-10-09 15:45:33 -04001758 IterState (list<Definition>::iterator tIter, list<Definition>::iterator tIterEnd)
Cary Clarkbad5ad72017-08-03 17:14:08 -04001759 : fDefIter(tIter)
1760 , fDefEnd(tIterEnd) {
1761 }
1762 list<Definition>::iterator fDefIter;
1763 list<Definition>::iterator fDefEnd;
1764 };
1765
Cary Clark73fa9722017-08-29 17:36:51 -04001766 struct ParentPair {
1767 const Definition* fParent;
1768 const ParentPair* fPrev;
1769 };
1770
Cary Clark8032b982017-07-28 11:04:54 -04001771 IncludeWriter() : IncludeParser() {}
1772 ~IncludeWriter() override {}
1773
1774 bool contentFree(int size, const char* data) const {
1775 while (size > 0 && data[0] <= ' ') {
1776 --size;
1777 ++data;
1778 }
1779 while (size > 0 && data[size - 1] <= ' ') {
1780 --size;
1781 }
1782 return 0 == size;
1783 }
1784
Cary Clark6fc50412017-09-21 12:31:06 -04001785 void descriptionOut(const Definition* def);
Cary Clark8032b982017-07-28 11:04:54 -04001786 void enumHeaderOut(const RootDefinition* root, const Definition& child);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001787 void enumMembersOut(const RootDefinition* root, Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001788 void enumSizeItems(const Definition& child);
1789 int lookupMethod(const PunctuationState punctuation, const Word word,
Ben Wagner63fd7602017-10-09 15:45:33 -04001790 const int start, const int run, int lastWrite,
Cary Clark6fc50412017-09-21 12:31:06 -04001791 const char* data, bool hasIndirection);
Cary Clark8032b982017-07-28 11:04:54 -04001792 int lookupReference(const PunctuationState punctuation, const Word word,
Ben Wagner63fd7602017-10-09 15:45:33 -04001793 const int start, const int run, int lastWrite, const char last,
Cary Clark8032b982017-07-28 11:04:54 -04001794 const char* data);
Cary Clark579985c2017-07-31 11:48:27 -04001795 void methodOut(const Definition* method, const Definition& child);
Cary Clark73fa9722017-08-29 17:36:51 -04001796 bool populate(Definition* def, ParentPair* parentPair, RootDefinition* root);
Cary Clark8032b982017-07-28 11:04:54 -04001797 bool populate(BmhParser& bmhParser);
1798
1799 void reset() override {
1800 INHERITED::resetCommon();
Cary Clark579985c2017-07-31 11:48:27 -04001801 fBmhMethod = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001802 fBmhParser = nullptr;
1803 fEnumDef = nullptr;
Cary Clark579985c2017-07-31 11:48:27 -04001804 fMethodDef = nullptr;
Cary Clark154beea2017-10-26 07:58:48 -04001805 fBmhStructDef = nullptr;
Cary Clark73fa9722017-08-29 17:36:51 -04001806 fAttrDeprecated = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001807 fAnonymousEnumCount = 1;
1808 fInStruct = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001809 fWroteMethod = false;
Cary Clark154beea2017-10-26 07:58:48 -04001810 fIndentNext = false;
1811 fPendingMethod = false;
Cary Clark8032b982017-07-28 11:04:54 -04001812 }
1813
1814 string resolveMethod(const char* start, const char* end, bool first);
Cary Clarkce101242017-09-01 15:51:02 -04001815 string resolveRef(const char* start, const char* end, bool first, RefType* refType);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001816 Wrote rewriteBlock(int size, const char* data, Phrase phrase);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001817 Definition* structMemberOut(const Definition* memberStart, const Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001818 void structOut(const Definition* root, const Definition& child,
1819 const char* commentStart, const char* commentEnd);
Cary Clark884dd7d2017-10-11 10:37:52 -04001820 void structSizeMembers(const Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001821
1822private:
1823 BmhParser* fBmhParser;
1824 Definition* fDeferComment;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001825 Definition* fLastComment;
Cary Clark579985c2017-07-31 11:48:27 -04001826 const Definition* fBmhMethod;
Cary Clark8032b982017-07-28 11:04:54 -04001827 const Definition* fEnumDef;
Cary Clark579985c2017-07-31 11:48:27 -04001828 const Definition* fMethodDef;
Cary Clark154beea2017-10-26 07:58:48 -04001829 const Definition* fBmhStructDef;
Cary Clark73fa9722017-08-29 17:36:51 -04001830 const Definition* fAttrDeprecated;
Cary Clark8032b982017-07-28 11:04:54 -04001831 const char* fContinuation; // used to construct paren-qualified method name
1832 int fAnonymousEnumCount;
1833 int fEnumItemValueTab;
1834 int fEnumItemCommentTab;
1835 int fStructMemberTab;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001836 int fStructValueTab;
Cary Clark8032b982017-07-28 11:04:54 -04001837 int fStructCommentTab;
1838 bool fInStruct;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001839 bool fWroteMethod;
Cary Clark154beea2017-10-26 07:58:48 -04001840 bool fIndentNext;
1841 bool fPendingMethod;
Cary Clark8032b982017-07-28 11:04:54 -04001842
1843 typedef IncludeParser INHERITED;
1844};
1845
1846class FiddleParser : public ParserCommon {
1847public:
1848 FiddleParser(BmhParser* bmh) : ParserCommon()
1849 , fBmhParser(bmh) {
1850 this->reset();
1851 }
1852
1853 Definition* findExample(const string& name) const;
1854
1855 bool parseFromFile(const char* path) override {
1856 if (!INHERITED::parseSetup(path)) {
1857 return false;
1858 }
1859 return parseFiddles();
1860 }
1861
1862 void reset() override {
1863 INHERITED::resetCommon();
1864 }
1865
1866private:
1867 bool parseFiddles();
1868
1869 BmhParser* fBmhParser; // must be writable; writes example hash
1870
1871 typedef ParserCommon INHERITED;
1872};
1873
1874class HackParser : public ParserCommon {
1875public:
1876 HackParser() : ParserCommon() {
1877 this->reset();
1878 }
1879
1880 bool parseFromFile(const char* path) override {
1881 if (!INHERITED::parseSetup(path)) {
1882 return false;
1883 }
1884 return hackFiles();
1885 }
1886
1887 void reset() override {
1888 INHERITED::resetCommon();
1889 }
1890
1891private:
1892 bool hackFiles();
1893
1894 typedef ParserCommon INHERITED;
1895};
1896
1897class MdOut : public ParserCommon {
1898public:
1899 MdOut(const BmhParser& bmh) : ParserCommon()
1900 , fBmhParser(bmh) {
1901 this->reset();
1902 }
1903
1904 bool buildReferences(const char* path, const char* outDir);
1905private:
1906 enum class TableState {
1907 kNone,
1908 kRow,
1909 kColumn,
1910 };
1911
1912 string addReferences(const char* start, const char* end, BmhParser::Resolvable );
1913 bool buildRefFromFile(const char* fileName, const char* outDir);
Cary Clarka523d2d2017-08-30 08:58:10 -04001914 bool checkParamReturnBody(const Definition* def) const;
Cary Clark8032b982017-07-28 11:04:54 -04001915 void childrenOut(const Definition* def, const char* contentStart);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001916 const Definition* findParamType();
Cary Clark8032b982017-07-28 11:04:54 -04001917 const Definition* isDefined(const TextParser& parser, const string& ref, bool report) const;
1918 string linkName(const Definition* ) const;
1919 string linkRef(const string& leadingSpaces, const Definition*, const string& ref) const;
1920 void markTypeOut(Definition* );
Ben Wagner63fd7602017-10-09 15:45:33 -04001921 void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); }
Cary Clark8032b982017-07-28 11:04:54 -04001922 void mdHeaderOutLF(int depth, int lf);
1923 bool parseFromFile(const char* path) override {
1924 return true;
1925 }
1926
1927 void reset() override {
1928 INHERITED::resetCommon();
Cary Clarkbad5ad72017-08-03 17:14:08 -04001929 fEnumClass = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001930 fMethod = nullptr;
1931 fRoot = nullptr;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001932 fLastParam = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001933 fTableState = TableState::kNone;
1934 fHasFiddle = false;
1935 fInDescription = false;
1936 fInList = false;
1937 }
1938
Cary Clark154beea2017-10-26 07:58:48 -04001939 BmhParser::Resolvable resolvable(const Definition* definition) const {
1940 MarkType markType = definition->fMarkType;
1941 if (MarkType::kCode == markType) {
1942 for (auto child : definition->fChildren) {
1943 if (MarkType::kLiteral == child->fMarkType) {
1944 return BmhParser::Resolvable::kLiteral;
1945 }
1946 }
1947 }
Ben Wagner63fd7602017-10-09 15:45:33 -04001948 if ((MarkType::kExample == markType
Cary Clark8032b982017-07-28 11:04:54 -04001949 || MarkType::kFunction == markType) && fHasFiddle) {
1950 return BmhParser::Resolvable::kNo;
1951 }
1952 return fBmhParser.fMaps[(int) markType].fResolve;
1953 }
1954
1955 void resolveOut(const char* start, const char* end, BmhParser::Resolvable );
1956
1957 const BmhParser& fBmhParser;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001958 const Definition* fEnumClass;
Cary Clark8032b982017-07-28 11:04:54 -04001959 Definition* fMethod;
1960 RootDefinition* fRoot;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001961 const Definition* fLastParam;
Cary Clark8032b982017-07-28 11:04:54 -04001962 TableState fTableState;
1963 bool fHasFiddle;
1964 bool fInDescription; // FIXME: for now, ignore unfound camelCase in description since it may
1965 // be defined in example which at present cannot be linked to
1966 bool fInList;
1967 typedef ParserCommon INHERITED;
1968};
1969
1970
1971// some methods cannot be trivially parsed; look for class-name / ~ / operator
1972class MethodParser : public TextParser {
1973public:
1974 MethodParser(const string& className, const string& fileName,
1975 const char* start, const char* end, int lineCount)
1976 : TextParser(fileName, start, end, lineCount)
1977 , fClassName(className) {
1978 }
1979
1980 void skipToMethodStart() {
1981 if (!fClassName.length()) {
1982 this->skipToAlphaNum();
1983 return;
1984 }
1985 while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
1986 this->next();
1987 }
1988 }
1989
1990 void skipToMethodEnd() {
1991 if (this->eof()) {
1992 return;
1993 }
1994 if (fClassName.length()) {
1995 if ('~' == this->peek()) {
1996 this->next();
1997 if (!this->startsWith(fClassName.c_str())) {
1998 --fChar;
1999 return;
2000 }
2001 }
2002 if (this->startsWith(fClassName.c_str()) || this->startsWith("operator")) {
2003 const char* ptr = this->anyOf(" (");
2004 if (ptr && '(' == *ptr) {
2005 this->skipToEndBracket(')');
2006 SkAssertResult(')' == this->next());
2007 return;
2008 }
2009 }
2010 }
2011 if (this->startsWith("Sk") && this->wordEndsWith(".h")) { // allow include refs
2012 this->skipToNonAlphaNum();
2013 } else {
2014 this->skipFullName();
2015 }
2016 }
2017
2018 bool wordEndsWith(const char* str) const {
2019 const char* space = this->strnchr(' ', fEnd);
2020 if (!space) {
2021 return false;
2022 }
2023 size_t len = strlen(str);
2024 if (space < fChar + len) {
2025 return false;
2026 }
2027 return !strncmp(str, space - len, len);
2028 }
2029
2030private:
2031 string fClassName;
2032 typedef TextParser INHERITED;
2033};
2034
2035#endif