blob: 6752225d527079d798d4e7d1cbc97465a21d9074 [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"
Cary Clark2f466242017-12-11 16:03:17 -050013#include "SkJSONCPP.h"
Cary Clark8032b982017-07-28 11:04:54 -040014
Ben Wagner63fd7602017-10-09 15:45:33 -040015#include <algorithm>
Cary Clark8032b982017-07-28 11:04:54 -040016#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
27template <typename T>
28std::string to_string(T value)
29{
30 std::ostringstream os ;
31 os << value ;
32 return os.str() ;
33}
34
35using std::forward_list;
36using std::list;
37using std::unordered_map;
38using std::string;
39using std::vector;
40
41enum class KeyWord {
42 kNone,
Cary Clark73fa9722017-08-29 17:36:51 -040043 kSK_API,
Cary Clark154beea2017-10-26 07:58:48 -040044 kSK_BEGIN_REQUIRE_DENSE,
Cary Clark8032b982017-07-28 11:04:54 -040045 kBool,
46 kChar,
47 kClass,
48 kConst,
49 kConstExpr,
50 kDefine,
51 kDouble,
52 kElif,
53 kElse,
54 kEndif,
55 kEnum,
56 kFloat,
57 kFriend,
58 kIf,
59 kIfdef,
60 kIfndef,
61 kInclude,
62 kInline,
63 kInt,
64 kOperator,
65 kPrivate,
66 kProtected,
67 kPublic,
68 kSigned,
69 kSize_t,
70 kStatic,
71 kStruct,
72 kTemplate,
73 kTypedef,
Cary Clarkd0530ba2017-09-14 11:25:39 -040074 kUint16_t,
Cary Clark8032b982017-07-28 11:04:54 -040075 kUint32_t,
Cary Clarkd0530ba2017-09-14 11:25:39 -040076 kUint64_t,
77 kUint8_t,
Cary Clark8032b982017-07-28 11:04:54 -040078 kUnion,
79 kUnsigned,
80 kVoid,
81};
82
83enum class MarkType {
84 kNone,
85 kAnchor,
86 kAlias,
87 kBug,
88 kClass,
89 kCode,
90 kColumn,
91 kComment,
92 kConst,
93 kDefine,
94 kDefinedBy,
95 kDeprecated,
96 kDescription,
97 kDoxygen,
Cary Clarkac47b882018-01-11 10:35:44 -050098 kDuration,
Cary Clark8032b982017-07-28 11:04:54 -040099 kEnum,
100 kEnumClass,
101 kError,
102 kExample,
103 kExperimental,
104 kExternal,
105 kFile,
106 kFormula,
107 kFunction,
108 kHeight,
109 kImage,
110 kLegend,
111 kLink,
112 kList,
Cary Clark154beea2017-10-26 07:58:48 -0400113 kLiteral, // don't lookup hyperlinks, do substitution, etc
Cary Clark8032b982017-07-28 11:04:54 -0400114 kMarkChar,
115 kMember,
116 kMethod,
117 kNoExample,
Cary Clark154beea2017-10-26 07:58:48 -0400118 kOutdent,
Cary Clark8032b982017-07-28 11:04:54 -0400119 kParam,
120 kPlatform,
121 kPrivate,
122 kReturn,
123 kRoot,
124 kRow,
125 kSeeAlso,
Cary Clark61dfc3a2018-01-03 08:37:53 -0500126 kSet,
Cary Clark8032b982017-07-28 11:04:54 -0400127 kStdOut,
128 kStruct,
129 kSubstitute,
130 kSubtopic,
131 kTable,
132 kTemplate,
133 kText,
134 kTime,
135 kToDo,
136 kTopic,
137 kTrack,
138 kTypedef,
139 kUnion,
140 kVolatile,
141 kWidth,
142};
143
144enum {
145 Last_MarkType = (int) MarkType::kWidth,
146};
147
148enum class Bracket {
149 kNone,
150 kParen,
151 kSquare,
152 kBrace,
153 kAngle,
154 kString,
155 kChar,
156 kSlashStar,
157 kSlashSlash,
158 kPound,
159 kColon,
Cary Clark73fa9722017-08-29 17:36:51 -0400160 kDebugCode, // parens get special treatment so SkDEBUGCODE( isn't treated as method
Cary Clark8032b982017-07-28 11:04:54 -0400161};
162
163enum class Punctuation { // catch-all for misc symbols tracked in C
164 kNone,
165 kAsterisk, // for pointer-to
166 kSemicolon, // e.g., to delinate xxx() const ; const int* yyy()
167 kLeftBrace,
168 kColon, // for foo() : bar(1), baz(2) {}
169};
170
Cary Clarkd0530ba2017-09-14 11:25:39 -0400171enum class KeyProperty {
172 kNone,
173 kClassSection,
174 kFunction,
175 kModifier,
176 kNumber,
177 kObject,
178 kPreprocessor,
179};
180
Cary Clark2f466242017-12-11 16:03:17 -0500181enum class StatusFilter {
182 kCompleted,
183 kInProgress,
184 kUnknown,
185};
186
Cary Clarkd0530ba2017-09-14 11:25:39 -0400187struct IncludeKey {
188 const char* fName;
189 KeyWord fKeyWord;
190 KeyProperty fProperty;
191};
192
193extern const IncludeKey kKeyWords[];
194
Cary Clark8032b982017-07-28 11:04:54 -0400195static inline bool has_nonwhitespace(const string& s) {
196 bool nonwhite = false;
197 for (const char& c : s) {
198 if (' ' < c) {
199 nonwhite = true;
200 break;
201 }
202 }
203 return nonwhite;
204}
205
206static inline void trim_end(string &s) {
207 s.erase(std::find_if(s.rbegin(), s.rend(),
208 std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
209}
210
211static inline void trim_end_spaces(string &s) {
212 while (s.length() > 0 && ' ' == s.back()) {
213 s.pop_back();
214 }
215}
216
217static inline void trim_start(string &s) {
218 s.erase(s.begin(), std::find_if(s.begin(), s.end(),
219 std::not1(std::ptr_fun<int, int>(std::isspace))));
220}
221
222static inline void trim_start_end(string& s) {
223 trim_start(s);
224 trim_end(s);
225}
226
227class NonAssignable {
228public:
229 NonAssignable(NonAssignable const&) = delete;
230 NonAssignable& operator=(NonAssignable const&) = delete;
231 NonAssignable() {}
232};
233
234class Definition;
235
236class TextParser : public NonAssignable {
237 TextParser() {} // only for ParserCommon to call
238 friend class ParserCommon;
239public:
Cary Clark2f466242017-12-11 16:03:17 -0500240 virtual ~TextParser() {}
Cary Clark8032b982017-07-28 11:04:54 -0400241 class Save {
242 public:
243 Save(TextParser* parser) {
244 fParser = parser;
245 fLine = parser->fLine;
246 fChar = parser->fChar;
247 fLineCount = parser->fLineCount;
248 }
249
250 void restore() const {
251 fParser->fLine = fLine;
252 fParser->fChar = fChar;
253 fParser->fLineCount = fLineCount;
254 }
255
256 private:
257 TextParser* fParser;
258 const char* fLine;
259 const char* fChar;
260 int fLineCount;
261 };
262
263 TextParser(const string& fileName, const char* start, const char* end, int lineCount)
264 : fFileName(fileName)
265 , fStart(start)
266 , fLine(start)
267 , fChar(start)
268 , fEnd(end)
269 , fLineCount(lineCount)
270 {
271 }
272
273 TextParser(const Definition* );
274
275 const char* anyOf(const char* str) const {
276 const char* ptr = fChar;
277 while (ptr < fEnd) {
278 if (strchr(str, ptr[0])) {
279 return ptr;
280 }
281 ++ptr;
282 }
283 return nullptr;
284 }
285
286 const char* anyOf(const char* wordStart, const char* wordList[], size_t wordListCount) const {
287 const char** wordPtr = wordList;
288 const char** wordEnd = wordPtr + wordListCount;
289 const size_t matchLen = fChar - wordStart;
290 while (wordPtr < wordEnd) {
291 const char* word = *wordPtr++;
292 if (strlen(word) == matchLen && !strncmp(wordStart, word, matchLen)) {
293 return word;
294 }
295 }
296 return nullptr;
297 }
298
299 char backup(const char* pattern) const {
300 size_t len = strlen(pattern);
301 const char* start = fChar - len;
302 if (start <= fStart) {
303 return '\0';
304 }
305 if (strncmp(start, pattern, len)) {
306 return '\0';
307 }
308 return start[-1];
309 }
310
311 bool contains(const char* match, const char* lineEnd, const char** loc) const {
312 *loc = this->strnstr(match, lineEnd);
313 return *loc;
314 }
315
Cary Clarka560c472017-11-27 10:44:06 -0500316 const char* doubleLF() const {
317 int count = 0;
318 const char* ptr = fChar;
319 const char* doubleStart = nullptr;
320 while (ptr < fEnd) {
321 if ('\n' == ptr[0]) {
322 if (++count == 1) {
323 doubleStart = ptr;
324 } else {
325 return doubleStart;
326 }
327 } else if (' ' < ptr[0]) {
328 count = 0;
329 }
330 ++ptr;
331 }
332 return nullptr;
333 }
334
335 bool endsWith(const char* match) {
336 int matchLen = strlen(match);
337 if (matchLen > fChar - fLine) {
338 return false;
339 }
340 return !strncmp(fChar - matchLen, match, matchLen);
341 }
342
Cary Clark8032b982017-07-28 11:04:54 -0400343 bool eof() const { return fChar >= fEnd; }
344
345 const char* lineEnd() const {
346 const char* ptr = fChar;
347 do {
348 if (ptr >= fEnd) {
349 return ptr;
350 }
351 char test = *ptr++;
352 if (test == '\n' || test == '\0') {
353 break;
354 }
355 } while (true);
356 return ptr;
357 }
358
359 ptrdiff_t lineLength() const {
360 return this->lineEnd() - fLine;
361 }
362
363 bool match(TextParser* );
364
Ben Wagner63fd7602017-10-09 15:45:33 -0400365 char next() {
Cary Clark8032b982017-07-28 11:04:54 -0400366 SkASSERT(fChar < fEnd);
367 char result = *fChar++;
368 if ('\n' == result) {
369 ++fLineCount;
370 fLine = fChar;
371 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400372 return result;
Cary Clark8032b982017-07-28 11:04:54 -0400373 }
374
375 char peek() const { SkASSERT(fChar < fEnd); return *fChar; }
376
377 void restorePlace(const TextParser& save) {
378 fChar = save.fChar;
379 fLine = save.fLine;
380 fLineCount = save.fLineCount;
381 }
382
383 void savePlace(TextParser* save) {
384 save->fChar = fChar;
385 save->fLine = fLine;
386 save->fLineCount = fLineCount;
387 }
388
389 void reportError(const char* errorStr) const;
390 void reportWarning(const char* errorStr) const;
391
392 template <typename T> T reportError(const char* errorStr) const {
393 this->reportError(errorStr);
394 return T();
395 }
396
397 bool sentenceEnd(const char* check) const {
398 while (check > fStart) {
399 --check;
400 if (' ' < check[0] && '.' != check[0]) {
401 return false;
402 }
403 if ('.' == check[0]) {
404 return ' ' >= check[1];
405 }
406 if ('\n' == check[0] && '\n' == check[1]) {
407 return true;
408 }
409 }
410 return true;
411 }
412
413 bool skipToEndBracket(char endBracket, const char* end = nullptr) {
414 if (nullptr == end) {
415 end = fEnd;
416 }
417 while (fChar[0] != endBracket) {
418 if (fChar >= end) {
419 return false;
420 }
421 (void) this->next();
422 }
423 return true;
424 }
425
426 bool skipToEndBracket(const char* endBracket) {
427 size_t len = strlen(endBracket);
428 while (strncmp(fChar, endBracket, len)) {
429 if (fChar >= fEnd) {
430 return false;
431 }
432 (void) this->next();
433 }
434 return true;
435 }
436
437 bool skipLine() {
438 return skipToEndBracket('\n');
439 }
440
441 void skipTo(const char* skip) {
442 while (fChar < skip) {
443 this->next();
444 }
445 }
446
447 void skipToAlpha() {
448 while (fChar < fEnd && !isalpha(fChar[0])) {
449 fChar++;
450 }
451 }
452
453 void skipToAlphaNum() {
454 while (fChar < fEnd && !isalnum(fChar[0])) {
455 fChar++;
456 }
457 }
458
459 bool skipExact(const char* pattern) {
460 if (!this->startsWith(pattern)) {
461 return false;
462 }
463 this->skipName(pattern);
464 return true;
465 }
466
467 // differs from skipToNonAlphaNum in that a.b isn't considered a full name,
468 // since a.b can't be found as a named definition
469 void skipFullName() {
470 while (fChar < fEnd && (isalnum(fChar[0])
Cary Clarka560c472017-11-27 10:44:06 -0500471 || '_' == fChar[0] /* || '-' == fChar[0] */
Cary Clark8032b982017-07-28 11:04:54 -0400472 || (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]))) {
473 if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
474 fChar++;
475 }
476 fChar++;
477 }
478 }
479
480 bool skipToLineStart() {
481 if (!this->skipLine()) {
482 return false;
483 }
484 if (!this->eof()) {
485 return this->skipWhiteSpace();
486 }
487 return true;
488 }
489
490 void skipToNonAlphaNum() {
491 while (fChar < fEnd && (isalnum(fChar[0])
492 || '_' == fChar[0] || '-' == fChar[0]
Cary Clarkce101242017-09-01 15:51:02 -0400493 || (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
Cary Clark8032b982017-07-28 11:04:54 -0400494 || ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
495 if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
496 fChar++;
497 }
498 fChar++;
499 }
500 }
501
502 void skipToSpace() {
503 while (fChar < fEnd && ' ' != fChar[0]) {
504 fChar++;
505 }
506 }
507
Cary Clarka560c472017-11-27 10:44:06 -0500508 void skipToWhiteSpace() {
509 while (fChar < fEnd && ' ' < fChar[0]) {
510 fChar++;
511 }
512 }
513
Cary Clark8032b982017-07-28 11:04:54 -0400514 bool skipName(const char* word) {
515 size_t len = strlen(word);
Cary Clarkce101242017-09-01 15:51:02 -0400516 if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
Cary Clarkd0530ba2017-09-14 11:25:39 -0400517 for (size_t i = 0; i < len; ++i) {
518 this->next();
519 }
Cary Clark8032b982017-07-28 11:04:54 -0400520 }
521 return this->eof() || ' ' >= fChar[0];
522 }
523
Ben Wagner63fd7602017-10-09 15:45:33 -0400524 bool skipSpace() {
525 while (' ' == this->peek()) {
Cary Clark8032b982017-07-28 11:04:54 -0400526 (void) this->next();
527 if (fChar >= fEnd) {
528 return false;
529 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400530 }
531 return true;
Cary Clark8032b982017-07-28 11:04:54 -0400532 }
533
534 bool skipWord(const char* word) {
535 if (!this->skipWhiteSpace()) {
536 return false;
537 }
538 const char* save = fChar;
539 if (!this->skipName(word)) {
540 fChar = save;
541 return false;
542 }
543 if (!this->skipWhiteSpace()) {
544 return false;
545 }
546 return true;
547 }
548
Ben Wagner63fd7602017-10-09 15:45:33 -0400549 bool skipWhiteSpace() {
550 while (' ' >= this->peek()) {
Cary Clark8032b982017-07-28 11:04:54 -0400551 (void) this->next();
552 if (fChar >= fEnd) {
553 return false;
554 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400555 }
556 return true;
Cary Clark8032b982017-07-28 11:04:54 -0400557 }
558
559 bool startsWith(const char* str) const {
560 size_t len = strlen(str);
Ben Wagner63fd7602017-10-09 15:45:33 -0400561 ptrdiff_t lineLen = fEnd - fChar;
Cary Clark8032b982017-07-28 11:04:54 -0400562 return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
563 }
564
Cary Clarkbad5ad72017-08-03 17:14:08 -0400565 // ignores minor white space differences
566 bool startsWith(const char* str, size_t oLen) const {
567 size_t tIndex = 0;
568 size_t tLen = fEnd - fChar;
569 size_t oIndex = 0;
570 while (oIndex < oLen && tIndex < tLen) {
571 bool tSpace = ' ' >= fChar[tIndex];
572 bool oSpace = ' ' >= str[oIndex];
573 if (tSpace != oSpace) {
574 break;
575 }
576 if (tSpace) {
577 do {
578 ++tIndex;
579 } while (tIndex < tLen && ' ' >= fChar[tIndex]);
580 do {
581 ++oIndex;
582 } while (oIndex < oLen && ' ' >= str[oIndex]);
583 continue;
584 }
585 if (fChar[tIndex] != str[oIndex]) {
586 break;
587 }
588 ++tIndex;
589 ++oIndex;
590 }
591 return oIndex >= oLen;
592 }
593
Cary Clark8032b982017-07-28 11:04:54 -0400594 const char* strnchr(char ch, const char* end) const {
595 const char* ptr = fChar;
596 while (ptr < end) {
597 if (ptr[0] == ch) {
598 return ptr;
599 }
600 ++ptr;
601 }
602 return nullptr;
603 }
604
605 const char* strnstr(const char *match, const char* end) const {
606 size_t matchLen = strlen(match);
607 SkASSERT(matchLen > 0);
608 ptrdiff_t len = end - fChar;
609 SkASSERT(len >= 0);
610 if ((size_t) len < matchLen ) {
611 return nullptr;
612 }
613 size_t count = len - matchLen;
614 for (size_t index = 0; index <= count; index++) {
615 if (0 == strncmp(&fChar[index], match, matchLen)) {
616 return &fChar[index];
617 }
618 }
619 return nullptr;
620 }
621
Cary Clarkce101242017-09-01 15:51:02 -0400622 const char* trimmedBracketEnd(const char bracket) const {
623 int max = (int) (this->lineLength());
Cary Clark8032b982017-07-28 11:04:54 -0400624 int index = 0;
625 while (index < max && bracket != fChar[index]) {
626 ++index;
627 }
628 SkASSERT(index < max);
629 while (index > 0 && ' ' >= fChar[index - 1]) {
630 --index;
631 }
632 return fChar + index;
633 }
634
635 const char* trimmedLineEnd() const {
636 const char* result = this->lineEnd();
637 while (result > fChar && ' ' >= result[-1]) {
638 --result;
639 }
640 return result;
641 }
642
643 void trimEnd() {
644 while (fEnd > fStart && ' ' >= fEnd[-1]) {
645 --fEnd;
646 }
647 }
648
Cary Clark2f466242017-12-11 16:03:17 -0500649 // FIXME: nothing else in TextParser knows from C++ --
650 // there could be a class between TextParser and ParserCommon
651 virtual string typedefName();
652
Cary Clark8032b982017-07-28 11:04:54 -0400653 const char* wordEnd() const {
654 const char* end = fChar;
655 while (isalnum(end[0]) || '_' == end[0] || '-' == end[0]) {
656 ++end;
657 }
658 return end;
659 }
660
661 string fFileName;
662 const char* fStart;
663 const char* fLine;
664 const char* fChar;
665 const char* fEnd;
666 size_t fLineCount;
667};
668
669class EscapeParser : public TextParser {
670public:
671 EscapeParser(const char* start, const char* end) :
672 TextParser("", start, end, 0) {
673 const char* reader = fStart;
674 fStorage = new char[end - start];
675 char* writer = fStorage;
676 while (reader < fEnd) {
677 char ch = *reader++;
678 if (ch != '\\') {
679 *writer++ = ch;
680 } else {
681 char ctrl = *reader++;
682 if (ctrl == 'u') {
683 unsigned unicode = 0;
684 for (int i = 0; i < 4; ++i) {
685 unicode <<= 4;
686 SkASSERT((reader[0] >= '0' && reader[0] <= '9') ||
Cary Clarka560c472017-11-27 10:44:06 -0500687 (reader[0] >= 'A' && reader[0] <= 'F') ||
688 (reader[0] >= 'a' && reader[0] <= 'f'));
Cary Clark8032b982017-07-28 11:04:54 -0400689 int nibble = *reader++ - '0';
690 if (nibble > 9) {
Cary Clarka560c472017-11-27 10:44:06 -0500691 nibble = (nibble & ~('a' - 'A')) - 'A' + '9' + 1;
Cary Clark8032b982017-07-28 11:04:54 -0400692 }
693 unicode |= nibble;
694 }
695 SkASSERT(unicode < 256);
696 *writer++ = (unsigned char) unicode;
697 } else {
698 SkASSERT(ctrl == 'n');
699 *writer++ = '\n';
700 }
701 }
702 }
703 fStart = fLine = fChar = fStorage;
704 fEnd = writer;
705 }
706
Cary Clark2f466242017-12-11 16:03:17 -0500707 ~EscapeParser() override {
Cary Clark8032b982017-07-28 11:04:54 -0400708 delete fStorage;
709 }
710private:
711 char* fStorage;
712};
713
714class RootDefinition;
715
716class Definition : public NonAssignable {
717public:
718 enum Type {
719 kNone,
720 kWord,
721 kMark,
722 kKeyWord,
723 kBracket,
724 kPunctuation,
725 kFileType,
726 };
727
728 enum class TrimExtract {
729 kNo,
730 kYes
731 };
732
Cary Clarkbef063a2017-10-31 15:44:45 -0400733 enum class ExampleOptions {
734 kText,
735 kPng,
736 kAll
737 };
738
Cary Clark8032b982017-07-28 11:04:54 -0400739 enum class MethodType {
740 kNone,
741 kConstructor,
742 kDestructor,
743 kOperator,
744 };
745
Cary Clarka560c472017-11-27 10:44:06 -0500746 enum class Operator {
747 kUnknown,
748 kAdd,
749 kAddTo,
750 kArray,
751 kCast,
752 kCopy,
753 kDelete,
754 kDereference,
755 kEqual,
756 kMinus,
757 kMove,
758 kMultiply,
759 kMultiplyBy,
760 kNew,
761 kNotEqual,
762 kSubtract,
763 kSubtractFrom,
764 };
765
Cary Clark8032b982017-07-28 11:04:54 -0400766 Definition() {}
767
Ben Wagner63fd7602017-10-09 15:45:33 -0400768 Definition(const char* start, const char* end, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400769 : fStart(start)
770 , fContentStart(start)
771 , fContentEnd(end)
772 , fParent(parent)
773 , fLineCount(line)
774 , fType(Type::kWord) {
775 if (parent) {
776 SkASSERT(parent->fFileName.length() > 0);
777 fFileName = parent->fFileName;
778 }
779 this->setParentIndex();
780 }
781
Ben Wagner63fd7602017-10-09 15:45:33 -0400782 Definition(MarkType markType, const char* start, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400783 : Definition(markType, start, nullptr, line, parent) {
784 }
785
Ben Wagner63fd7602017-10-09 15:45:33 -0400786 Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400787 : Definition(start, end, line, parent) {
788 fMarkType = markType;
Ben Wagner63fd7602017-10-09 15:45:33 -0400789 fType = Type::kMark;
Cary Clark8032b982017-07-28 11:04:54 -0400790 }
791
Ben Wagner63fd7602017-10-09 15:45:33 -0400792 Definition(Bracket bracket, const char* start, int lineCount, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400793 : Definition(start, nullptr, lineCount, parent) {
794 fBracket = bracket;
795 fType = Type::kBracket;
796 }
797
Ben Wagner63fd7602017-10-09 15:45:33 -0400798 Definition(KeyWord keyWord, const char* start, const char* end, int lineCount,
799 Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400800 : Definition(start, end, lineCount, parent) {
801 fKeyWord = keyWord;
802 fType = Type::kKeyWord;
803 }
804
Ben Wagner63fd7602017-10-09 15:45:33 -0400805 Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400806 : Definition(start, nullptr, lineCount, parent) {
807 fPunctuation = punctuation;
808 fType = Type::kPunctuation;
809 }
810
811 virtual ~Definition() {}
812
813 virtual RootDefinition* asRoot() { SkASSERT(0); return nullptr; }
814 virtual const RootDefinition* asRoot() const { SkASSERT(0); return nullptr; }
Cary Clarka560c472017-11-27 10:44:06 -0500815 bool boilerplateIfDef(Definition* parent);
816 bool boilerplateDef(Definition* parent);
Cary Clark8032b982017-07-28 11:04:54 -0400817
818 bool boilerplateEndIf() {
819 return true;
820 }
821
822 bool checkMethod() const;
Cary Clark73fa9722017-08-29 17:36:51 -0400823 bool crossCheck2(const Definition& includeToken) const;
Cary Clark8032b982017-07-28 11:04:54 -0400824 bool crossCheck(const Definition& includeToken) const;
825 bool crossCheckInside(const char* start, const char* end, const Definition& includeToken) const;
Cary Clarkbef063a2017-10-31 15:44:45 -0400826 bool exampleToScript(string* result, ExampleOptions ) const;
Cary Clarka560c472017-11-27 10:44:06 -0500827 string extractText(TrimExtract trimExtract) const;
Cary Clark8032b982017-07-28 11:04:54 -0400828 string fiddleName() const;
829 string formatFunction() const;
830 const Definition* hasChild(MarkType markType) const;
Cary Clarkac47b882018-01-11 10:35:44 -0500831 bool hasMatch(const string& name) const;
Cary Clark8032b982017-07-28 11:04:54 -0400832 const Definition* hasParam(const string& ref) const;
833 bool isClone() const { return fClone; }
834
835 Definition* iRootParent() {
836 Definition* test = fParent;
837 while (test) {
838 if (Type::kKeyWord == test->fType && KeyWord::kClass == test->fKeyWord) {
839 return test;
840 }
841 test = test->fParent;
842 }
843 return nullptr;
844 }
845
846 virtual bool isRoot() const { return false; }
847
848 int length() const {
849 return (int) (fContentEnd - fContentStart);
850 }
851
852 bool methodHasReturn(const string& name, TextParser* methodParser) const;
853 string methodName() const;
Ben Wagner63fd7602017-10-09 15:45:33 -0400854 bool nextMethodParam(TextParser* methodParser, const char** nextEndPtr,
Cary Clark8032b982017-07-28 11:04:54 -0400855 string* paramName) const;
Cary Clarka560c472017-11-27 10:44:06 -0500856 static string NormalizedName(string name);
Cary Clark8032b982017-07-28 11:04:54 -0400857 bool paramsMatch(const string& fullRef, const string& name) const;
Cary Clarka560c472017-11-27 10:44:06 -0500858 bool parseOperator(size_t doubleColons, string& result);
Cary Clark8032b982017-07-28 11:04:54 -0400859
860 string printableName() const {
861 string result(fName);
862 std::replace(result.begin(), result.end(), '_', ' ');
863 return result;
864 }
865
Cary Clark9174bda2017-09-19 17:39:32 -0400866 template <typename T> T reportError(const char* errorStr) const {
867 TextParser tp(this);
868 tp.reportError(errorStr);
869 return T();
870 }
871
Cary Clark8032b982017-07-28 11:04:54 -0400872 virtual RootDefinition* rootParent() { SkASSERT(0); return nullptr; }
Cary Clarka560c472017-11-27 10:44:06 -0500873 void setCanonicalFiddle();
Cary Clark8032b982017-07-28 11:04:54 -0400874
875 void setParentIndex() {
876 fParentIndex = fParent ? (int) fParent->fTokens.size() : -1;
877 }
878
Cary Clarka560c472017-11-27 10:44:06 -0500879 void setWrapper();
880
Cary Clark8032b982017-07-28 11:04:54 -0400881 string fText; // if text is constructed instead of in a file, it's put here
882 const char* fStart = nullptr; // .. in original text file, or the start of fText
883 const char* fContentStart; // start past optional markup name
884 string fName;
885 string fFiddle; // if its a constructor or operator, fiddle name goes here
886 const char* fContentEnd = nullptr; // the end of the contained text
887 const char* fTerminator = nullptr; // the end of the markup, normally ##\n or \n
888 Definition* fParent = nullptr;
889 list<Definition> fTokens;
890 vector<Definition*> fChildren;
891 string fHash; // generated by fiddle
892 string fFileName;
Cary Clarka560c472017-11-27 10:44:06 -0500893 mutable string fWrapper; // used by Example to wrap into proper function
Cary Clark8032b982017-07-28 11:04:54 -0400894 size_t fLineCount = 0;
895 int fParentIndex = 0;
896 MarkType fMarkType = MarkType::kNone;
897 KeyWord fKeyWord = KeyWord::kNone;
898 Bracket fBracket = Bracket::kNone;
899 Punctuation fPunctuation = Punctuation::kNone;
900 MethodType fMethodType = MethodType::kNone;
Cary Clarka560c472017-11-27 10:44:06 -0500901 Operator fOperator = Operator::kUnknown;
Cary Clark8032b982017-07-28 11:04:54 -0400902 Type fType = Type::kNone;
903 bool fClone = false;
904 bool fCloned = false;
Cary Clarka560c472017-11-27 10:44:06 -0500905 bool fOperatorConst = false;
Cary Clark8032b982017-07-28 11:04:54 -0400906 bool fPrivate = false;
907 bool fShort = false;
908 bool fMemberStart = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -0400909 bool fAnonymous = false;
Cary Clark8032b982017-07-28 11:04:54 -0400910 mutable bool fVisited = false;
911};
912
913class RootDefinition : public Definition {
914public:
Cary Clarkce101242017-09-01 15:51:02 -0400915 enum class AllowParens {
916 kNo,
917 kYes,
918 };
919
Cary Clark8032b982017-07-28 11:04:54 -0400920 RootDefinition() {
921 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400922
Cary Clark8032b982017-07-28 11:04:54 -0400923 RootDefinition(MarkType markType, const char* start, int line, Definition* parent)
924 : Definition(markType, start, line, parent) {
925 }
926
Ben Wagner63fd7602017-10-09 15:45:33 -0400927 RootDefinition(MarkType markType, const char* start, const char* end, int line,
Cary Clark8032b982017-07-28 11:04:54 -0400928 Definition* parent) : Definition(markType, start, end, line, parent) {
929 }
930
931 ~RootDefinition() override {
932 for (auto& iter : fBranches) {
933 delete iter.second;
934 }
935 }
936
937 RootDefinition* asRoot() override { return this; }
938 const RootDefinition* asRoot() const override { return this; }
939 void clearVisited();
Cary Clarkf5404bb2018-01-05 12:10:09 -0500940 bool dumpUnVisited();
Cary Clarkce101242017-09-01 15:51:02 -0400941 const Definition* find(const string& ref, AllowParens ) const;
Cary Clark8032b982017-07-28 11:04:54 -0400942 bool isRoot() const override { return true; }
943 RootDefinition* rootParent() override { return fRootParent; }
944 void setRootParent(RootDefinition* rootParent) { fRootParent = rootParent; }
945
946 unordered_map<string, RootDefinition*> fBranches;
947 unordered_map<string, Definition> fLeaves;
948private:
949 RootDefinition* fRootParent = nullptr;
950};
951
952struct IClassDefinition : public Definition {
953 unordered_map<string, Definition*> fEnums;
954 unordered_map<string, Definition*> fMembers;
955 unordered_map<string, Definition*> fMethods;
956 unordered_map<string, Definition*> fStructs;
Cary Clark2f466242017-12-11 16:03:17 -0500957 unordered_map<string, Definition*> fTypedefs;
Cary Clark8032b982017-07-28 11:04:54 -0400958};
959
960struct Reference {
961 Reference()
962 : fLocation(nullptr)
963 , fDefinition(nullptr) {
964 }
965
966 const char* fLocation; // .. in original text file
967 const Definition* fDefinition;
968};
969
970struct TypeNames {
971 const char* fName;
972 MarkType fMarkType;
973};
974
975class ParserCommon : public TextParser {
976public:
977
978 ParserCommon() : TextParser()
979 , fParent(nullptr)
Cary Clarkd0530ba2017-09-14 11:25:39 -0400980 , fDebugOut(false)
Cary Clark8032b982017-07-28 11:04:54 -0400981 {
982 }
983
Cary Clark2f466242017-12-11 16:03:17 -0500984 ~ParserCommon() override {
Cary Clark8032b982017-07-28 11:04:54 -0400985 }
986
987 void addDefinition(Definition* def) {
988 fParent->fChildren.push_back(def);
989 fParent = def;
990 }
991
992 void indentToColumn(int column) {
993 SkASSERT(column >= fColumn);
Cary Clarkd0530ba2017-09-14 11:25:39 -0400994 if (fDebugOut) {
995 SkDebugf("%*s", column - fColumn, "");
996 }
Cary Clark8032b982017-07-28 11:04:54 -0400997 fprintf(fOut, "%*s", column - fColumn, "");
998 fColumn = column;
999 fSpaces += column - fColumn;
1000 }
1001
1002 bool leadingPunctuation(const char* str, size_t len) const {
1003 if (!fPendingSpace) {
1004 return false;
1005 }
1006 if (len < 2) {
1007 return false;
1008 }
1009 if ('.' != str[0] && ',' != str[0] && ';' != str[0] && ':' != str[0]) {
1010 return false;
1011 }
1012 return ' ' >= str[1];
1013 }
1014
1015 void lf(int count) {
1016 fPendingLF = SkTMax(fPendingLF, count);
1017 this->nl();
1018 }
1019
1020 void lfAlways(int count) {
1021 this->lf(count);
1022 this->writePending();
1023 }
1024
1025 void lfcr() {
1026 this->lf(1);
1027 }
1028
1029 void nl() {
1030 fLinefeeds = 0;
1031 fSpaces = 0;
1032 fColumn = 0;
Cary Clark9174bda2017-09-19 17:39:32 -04001033 fPendingSpace = 0;
Cary Clark8032b982017-07-28 11:04:54 -04001034 }
1035
1036 bool parseFile(const char* file, const char* suffix);
Cary Clark2f466242017-12-11 16:03:17 -05001037 bool parseStatus(const char* file, const char* suffix, StatusFilter filter);
Cary Clark8032b982017-07-28 11:04:54 -04001038 virtual bool parseFromFile(const char* path) = 0;
1039 bool parseSetup(const char* path);
1040
1041 void popObject() {
1042 fParent->fContentEnd = fParent->fTerminator = fChar;
1043 fParent = fParent->fParent;
1044 }
1045
Cary Clark7cfcbca2018-01-04 16:11:51 -05001046 const char* ReadToBuffer(string filename, int* size);
1047
Cary Clark8032b982017-07-28 11:04:54 -04001048 virtual void reset() = 0;
1049
1050 void resetCommon() {
1051 fLine = fChar = fStart;
1052 fLineCount = 0;
1053 fParent = nullptr;
1054 fIndent = 0;
1055 fOut = nullptr;
1056 fMaxLF = 2;
1057 fPendingLF = 0;
Cary Clark9174bda2017-09-19 17:39:32 -04001058 fPendingSpace = 0;
Cary Clark154beea2017-10-26 07:58:48 -04001059 fOutdentNext = false;
Cary Clark8032b982017-07-28 11:04:54 -04001060 nl();
1061 }
1062
1063 void setAsParent(Definition* definition) {
1064 if (fParent) {
1065 fParent->fChildren.push_back(definition);
1066 definition->fParent = fParent;
1067 }
1068 fParent = definition;
1069 }
1070
1071 void singleLF() {
1072 fMaxLF = 1;
1073 }
1074
Cary Clark8032b982017-07-28 11:04:54 -04001075 void writeBlock(int size, const char* data) {
1076 SkAssertResult(writeBlockTrim(size, data));
1077 }
Cary Clark154beea2017-10-26 07:58:48 -04001078
1079 void writeBlockIndent(int size, const char* data);
1080 bool writeBlockTrim(int size, const char* data);
1081
Cary Clark8032b982017-07-28 11:04:54 -04001082 void writeCommentHeader() {
1083 this->lf(2);
1084 this->writeString("/**");
1085 this->writeSpace();
1086 }
1087
1088 void writeCommentTrailer() {
1089 this->writeString("*/");
1090 this->lfcr();
1091 }
1092
Cary Clark154beea2017-10-26 07:58:48 -04001093 void writePending();
1094
Cary Clark8032b982017-07-28 11:04:54 -04001095 // write a pending space, so that two consecutive calls
1096 // don't double write, and trailing spaces on lines aren't written
Cary Clark9174bda2017-09-19 17:39:32 -04001097 void writeSpace(int count = 1) {
Cary Clark8032b982017-07-28 11:04:54 -04001098 SkASSERT(!fPendingLF);
1099 SkASSERT(!fLinefeeds);
1100 SkASSERT(fColumn > 0);
1101 SkASSERT(!fSpaces);
Cary Clark9174bda2017-09-19 17:39:32 -04001102 fPendingSpace = count;
Cary Clark8032b982017-07-28 11:04:54 -04001103 }
1104
Cary Clark154beea2017-10-26 07:58:48 -04001105 void writeString(const char* str);
Cary Clark8032b982017-07-28 11:04:54 -04001106
Cary Clark9174bda2017-09-19 17:39:32 -04001107 void writeString(const string& str) {
1108 this->writeString(str.c_str());
1109 }
1110
Cary Clark7cfcbca2018-01-04 16:11:51 -05001111 bool writtenFileDiffers(string filename, string readname);
Cary Clark8032b982017-07-28 11:04:54 -04001112
1113 unordered_map<string, sk_sp<SkData>> fRawData;
1114 unordered_map<string, vector<char>> fLFOnly;
1115 Definition* fParent;
1116 FILE* fOut;
1117 int fLinefeeds; // number of linefeeds last written, zeroed on non-space
Cary Clark9174bda2017-09-19 17:39:32 -04001118 int fMaxLF; // number of linefeeds allowed
1119 int fPendingLF; // number of linefeeds to write (can be suppressed)
1120 int fSpaces; // number of spaces (indent) last written, zeroed on non-space
1121 int fColumn; // current column; number of chars past last linefeed
1122 int fIndent; // desired indention
1123 int fPendingSpace; // one or two spaces should preceed the next string or block
1124 char fLastChar; // last written
1125 bool fDebugOut; // set true to write to std out
Cary Clark154beea2017-10-26 07:58:48 -04001126 bool fOutdentNext; // set at end of embedded struct to prevent premature outdent
Cary Clark8032b982017-07-28 11:04:54 -04001127private:
1128 typedef TextParser INHERITED;
1129};
1130
Cary Clark2f466242017-12-11 16:03:17 -05001131struct JsonStatus {
1132 const Json::Value& fObject;
1133 Json::Value::iterator fIter;
1134 string fName;
1135};
Cary Clark8032b982017-07-28 11:04:54 -04001136
Cary Clark2f466242017-12-11 16:03:17 -05001137class StatusIter : public ParserCommon {
1138public:
1139 StatusIter(const char* statusFile, const char* suffix, StatusFilter);
1140 ~StatusIter() override {}
1141 string baseDir();
1142 bool empty() { return fStack.empty(); }
1143 bool next(string* file);
1144protected:
1145 bool parseFromFile(const char* path) override;
1146 void reset() override;
1147private:
1148 vector<JsonStatus> fStack;
1149 Json::Value fRoot;
1150 const char* fSuffix;
1151 StatusFilter fFilter;
1152};
Cary Clark8032b982017-07-28 11:04:54 -04001153
1154class BmhParser : public ParserCommon {
1155public:
1156 enum class MarkLookup {
1157 kRequire,
1158 kAllowUnknown,
1159 };
1160
1161 enum class Resolvable {
1162 kNo, // neither resolved nor output
1163 kYes, // resolved, output
1164 kOut, // not resolved, but output
Cary Clark154beea2017-10-26 07:58:48 -04001165 kLiteral, // output untouched (FIXME: is this really different from kOut?)
Cary Clark8032b982017-07-28 11:04:54 -04001166 };
1167
1168 enum class Exemplary {
1169 kNo,
1170 kYes,
1171 kOptional,
1172 };
1173
Cary Clarkce101242017-09-01 15:51:02 -04001174 enum class TableState {
1175 kNone,
1176 kColumnStart,
1177 kColumnEnd,
1178 };
1179
Cary Clark8032b982017-07-28 11:04:54 -04001180#define M(mt) (1LL << (int) MarkType::k##mt)
1181#define M_D M(Description)
1182#define M_CS M(Class) | M(Struct)
1183#define M_ST M(Subtopic) | M(Topic)
1184#define M_CSST M_CS | M_ST
1185#ifdef M_E
1186#undef M_E
1187#endif
1188#define M_E M(Enum) | M(EnumClass)
1189
1190#define R_Y Resolvable::kYes
1191#define R_N Resolvable::kNo
1192#define R_O Resolvable::kOut
1193
1194#define E_Y Exemplary::kYes
1195#define E_N Exemplary::kNo
1196#define E_O Exemplary::kOptional
1197
Cary Clarka560c472017-11-27 10:44:06 -05001198 BmhParser(bool skip) : ParserCommon()
Ben Wagner63fd7602017-10-09 15:45:33 -04001199 , fMaps {
Cary Clark8032b982017-07-28 11:04:54 -04001200// names without formal definitions (e.g. Column) aren't included
1201// fill in other names once they're actually used
Cary Clarkce101242017-09-01 15:51:02 -04001202 { "", nullptr, MarkType::kNone, R_Y, E_N, 0 }
Cary Clark7cfcbca2018-01-04 16:11:51 -05001203, { "A", nullptr, MarkType::kAnchor, R_N, E_N, 0 }
Cary Clarkce101242017-09-01 15:51:02 -04001204, { "Alias", nullptr, MarkType::kAlias, R_N, E_N, 0 }
1205, { "Bug", nullptr, MarkType::kBug, R_N, E_N, 0 }
1206, { "Class", &fClassMap, MarkType::kClass, R_Y, E_O, M_CSST | M(Root) }
Cary Clark154beea2017-10-26 07:58:48 -04001207, { "Code", nullptr, MarkType::kCode, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clarkce101242017-09-01 15:51:02 -04001208, { "", nullptr, MarkType::kColumn, R_Y, E_N, M(Row) }
1209, { "", nullptr, MarkType::kComment, R_N, E_N, 0 }
1210, { "Const", &fConstMap, MarkType::kConst, R_Y, E_N, M_E | M_ST }
1211, { "Define", nullptr, MarkType::kDefine, R_O, E_N, M_ST }
1212, { "DefinedBy", nullptr, MarkType::kDefinedBy, R_N, E_N, M(Method) }
1213, { "Deprecated", nullptr, MarkType::kDeprecated, R_Y, E_N, 0 }
Cary Clarkac47b882018-01-11 10:35:44 -05001214, { "Description", nullptr, MarkType::kDescription, R_Y, E_N, M(Example) | M(NoExample) }
Cary Clarkce101242017-09-01 15:51:02 -04001215, { "Doxygen", nullptr, MarkType::kDoxygen, R_Y, E_N, 0 }
Cary Clarkac47b882018-01-11 10:35:44 -05001216, { "Duration", nullptr, MarkType::kDuration, R_N, E_N, M(Example) | M(NoExample) }
Cary Clarkce101242017-09-01 15:51:02 -04001217, { "Enum", &fEnumMap, MarkType::kEnum, R_Y, E_O, M_CSST | M(Root) }
1218, { "EnumClass", &fClassMap, MarkType::kEnumClass, R_Y, E_O, M_CSST | M(Root) }
Cary Clarkac47b882018-01-11 10:35:44 -05001219, { "Error", nullptr, MarkType::kError, R_N, E_N, M(Example) | M(NoExample) }
Cary Clarkce101242017-09-01 15:51:02 -04001220, { "Example", nullptr, MarkType::kExample, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clarkbad5ad72017-08-03 17:14:08 -04001221, { "Experimental", nullptr, MarkType::kExperimental, R_Y, E_N, 0 }
Cary Clarkce101242017-09-01 15:51:02 -04001222, { "External", nullptr, MarkType::kExternal, R_Y, E_N, M(Root) }
1223, { "File", nullptr, MarkType::kFile, R_N, E_N, M(Track) }
Ben Wagner63fd7602017-10-09 15:45:33 -04001224, { "Formula", nullptr, MarkType::kFormula, R_O, E_N,
Cary Clarkce101242017-09-01 15:51:02 -04001225 M(Column) | M_ST | M(Member) | M(Method) | M_D }
Cary Clarkac47b882018-01-11 10:35:44 -05001226, { "Function", nullptr, MarkType::kFunction, R_O, E_N, M(Example) | M(NoExample) }
1227, { "Height", nullptr, MarkType::kHeight, R_N, E_N, M(Example) | M(NoExample) }
1228, { "Image", nullptr, MarkType::kImage, R_N, E_N, M(Example) | M(NoExample) }
Cary Clarkce101242017-09-01 15:51:02 -04001229, { "Legend", nullptr, MarkType::kLegend, R_Y, E_N, M(Table) }
1230, { "", nullptr, MarkType::kLink, R_N, E_N, M(Anchor) }
1231, { "List", nullptr, MarkType::kList, R_Y, E_N, M(Method) | M_CSST | M_E | M_D }
Cary Clark154beea2017-10-26 07:58:48 -04001232, { "Literal", nullptr, MarkType::kLiteral, R_N, E_N, M(Code) }
Cary Clarkce101242017-09-01 15:51:02 -04001233, { "", nullptr, MarkType::kMarkChar, R_N, E_N, 0 }
1234, { "Member", nullptr, MarkType::kMember, R_Y, E_N, M(Class) | M(Struct) }
1235, { "Method", &fMethodMap, MarkType::kMethod, R_Y, E_Y, M_CSST }
Cary Clarkac47b882018-01-11 10:35:44 -05001236, { "NoExample", nullptr, MarkType::kNoExample, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clark154beea2017-10-26 07:58:48 -04001237, { "Outdent", nullptr, MarkType::kOutdent, R_N, E_N, M(Code) }
Cary Clarkce101242017-09-01 15:51:02 -04001238, { "Param", nullptr, MarkType::kParam, R_Y, E_N, M(Method) }
Cary Clarkac47b882018-01-11 10:35:44 -05001239, { "Platform", nullptr, MarkType::kPlatform, R_N, E_N, M(Example) | M(NoExample) }
Cary Clarkce101242017-09-01 15:51:02 -04001240, { "Private", nullptr, MarkType::kPrivate, R_N, E_N, 0 }
1241, { "Return", nullptr, MarkType::kReturn, R_Y, E_N, M(Method) }
1242, { "", nullptr, MarkType::kRoot, R_Y, E_N, 0 }
1243, { "", nullptr, MarkType::kRow, R_Y, E_N, M(Table) | M(List) }
Cary Clark3cd22cc2017-12-01 11:49:58 -05001244, { "SeeAlso", nullptr, MarkType::kSeeAlso, R_Y, E_N,
1245 M_CSST | M_E | M(Method) | M(Typedef) }
Cary Clarkac47b882018-01-11 10:35:44 -05001246, { "Set", nullptr, MarkType::kSet, R_N, E_N, M(Example) | M(NoExample) }
1247, { "StdOut", nullptr, MarkType::kStdOut, R_N, E_N, M(Example) | M(NoExample) }
Cary Clarkce101242017-09-01 15:51:02 -04001248, { "Struct", &fClassMap, MarkType::kStruct, R_Y, E_O, M(Class) | M(Root) | M_ST }
1249, { "Substitute", nullptr, MarkType::kSubstitute, R_N, E_N, M_ST }
1250, { "Subtopic", nullptr, MarkType::kSubtopic, R_Y, E_Y, M_CSST }
1251, { "Table", nullptr, MarkType::kTable, R_Y, E_N, M(Method) | M_CSST | M_E }
1252, { "Template", nullptr, MarkType::kTemplate, R_Y, E_N, 0 }
1253, { "", nullptr, MarkType::kText, R_Y, E_N, 0 }
1254, { "Time", nullptr, MarkType::kTime, R_Y, E_N, M(Track) }
1255, { "ToDo", nullptr, MarkType::kToDo, R_N, E_N, 0 }
1256, { "Topic", nullptr, MarkType::kTopic, R_Y, E_Y, M_CS | M(Root) | M(Topic) }
1257, { "Track", nullptr, MarkType::kTrack, R_Y, E_N, M_E | M_ST }
Cary Clarka560c472017-11-27 10:44:06 -05001258, { "Typedef", &fTypedefMap, MarkType::kTypedef, R_Y, E_N, M(Class) | M_ST }
Cary Clarkce101242017-09-01 15:51:02 -04001259, { "", nullptr, MarkType::kUnion, R_Y, E_N, 0 }
1260, { "Volatile", nullptr, MarkType::kVolatile, R_N, E_N, M(StdOut) }
Cary Clarkac47b882018-01-11 10:35:44 -05001261, { "Width", nullptr, MarkType::kWidth, R_N, E_N, M(Example) | M(NoExample) } }
Cary Clarka560c472017-11-27 10:44:06 -05001262, fSkip(skip)
Cary Clark8032b982017-07-28 11:04:54 -04001263 {
1264 this->reset();
1265 }
1266
1267#undef R_O
1268#undef R_N
1269#undef R_Y
1270
1271#undef M_E
1272#undef M_CSST
1273#undef M_ST
1274#undef M_CS
1275#undef M_D
1276#undef M
1277
1278 ~BmhParser() override {}
1279
1280 bool addDefinition(const char* defStart, bool hasEnd, MarkType markType,
1281 const vector<string>& typeNameBuilder);
Cary Clark73fa9722017-08-29 17:36:51 -04001282 bool checkExamples() const;
Cary Clarka523d2d2017-08-30 08:58:10 -04001283 bool checkParamReturn(const Definition* definition) const;
Cary Clark73fa9722017-08-29 17:36:51 -04001284 bool dumpExamples(const char* fiddleJsonFileName) const;
Cary Clark8032b982017-07-28 11:04:54 -04001285 bool childOf(MarkType markType) const;
1286 string className(MarkType markType);
1287 bool collectExternals();
1288 int endHashCount() const;
Cary Clarkce101242017-09-01 15:51:02 -04001289 bool endTableColumn(const char* end, const char* terminator);
Cary Clark8032b982017-07-28 11:04:54 -04001290
1291 RootDefinition* findBmhObject(MarkType markType, const string& typeName) {
1292 auto map = fMaps[(int) markType].fBmh;
1293 if (!map) {
1294 return nullptr;
1295 }
1296 return &(*map)[typeName];
1297 }
1298
1299 bool findDefinitions();
1300 MarkType getMarkType(MarkLookup lookup) const;
1301 bool hasEndToken() const;
1302 string memberName();
1303 string methodName();
1304 const Definition* parentSpace() const;
1305
1306 bool parseFromFile(const char* path) override {
1307 if (!INHERITED::parseSetup(path)) {
1308 return false;
1309 }
1310 fCheckMethods = !strstr(path, "undocumented.bmh");
1311 return findDefinitions();
1312 }
1313
1314 bool popParentStack(Definition* definition);
Cary Clark73fa9722017-08-29 17:36:51 -04001315 void reportDuplicates(const Definition& def, const string& dup) const;
Cary Clark8032b982017-07-28 11:04:54 -04001316
1317 void reset() override {
1318 INHERITED::resetCommon();
1319 fRoot = nullptr;
Cary Clarkce101242017-09-01 15:51:02 -04001320 fWorkingColumn = nullptr;
1321 fRow = nullptr;
1322 fTableState = TableState::kNone;
Cary Clark8032b982017-07-28 11:04:54 -04001323 fMC = '#';
1324 fInChar = false;
1325 fInCharCommentString = false;
1326 fInComment = false;
1327 fInEnum = false;
1328 fInString = false;
1329 fCheckMethods = false;
1330 }
1331
1332 bool skipNoName();
1333 bool skipToDefinitionEnd(MarkType markType);
Cary Clarkce101242017-09-01 15:51:02 -04001334 void spellCheck(const char* match, SkCommandLineFlags::StringArray report) const;
Cary Clark2f466242017-12-11 16:03:17 -05001335 void spellStatus(const char* match, SkCommandLineFlags::StringArray report) const;
Cary Clark8032b982017-07-28 11:04:54 -04001336 vector<string> topicName();
1337 vector<string> typeName(MarkType markType, bool* expectEnd);
Cary Clark2f466242017-12-11 16:03:17 -05001338 string typedefName() override;
Cary Clark8032b982017-07-28 11:04:54 -04001339 string uniqueName(const string& base, MarkType markType);
1340 string uniqueRootName(const string& base, MarkType markType);
1341 void validate() const;
1342 string word(const string& prefix, const string& delimiter);
1343
1344public:
1345 struct DefinitionMap {
1346 const char* fName;
1347 unordered_map<string, RootDefinition>* fBmh;
1348 MarkType fMarkType;
1349 Resolvable fResolve;
1350 Exemplary fExemplary; // worthy of an example
1351 uint64_t fParentMask;
1352 };
Ben Wagner63fd7602017-10-09 15:45:33 -04001353
Cary Clark8032b982017-07-28 11:04:54 -04001354 DefinitionMap fMaps[Last_MarkType + 1];
1355 forward_list<RootDefinition> fTopics;
1356 forward_list<Definition> fMarkup;
1357 forward_list<RootDefinition> fExternals;
1358 vector<string> fInputFiles;
1359 unordered_map<string, RootDefinition> fClassMap;
1360 unordered_map<string, RootDefinition> fConstMap;
1361 unordered_map<string, RootDefinition> fEnumMap;
1362 unordered_map<string, RootDefinition> fMethodMap;
1363 unordered_map<string, RootDefinition> fTypedefMap;
1364 unordered_map<string, Definition*> fTopicMap;
1365 unordered_map<string, Definition*> fAliasMap;
1366 RootDefinition* fRoot;
Cary Clarkce101242017-09-01 15:51:02 -04001367 Definition* fWorkingColumn;
1368 Definition* fRow;
1369 const char* fColStart;
1370 TableState fTableState;
Cary Clark8032b982017-07-28 11:04:54 -04001371 mutable char fMC; // markup character
1372 bool fAnonymous;
1373 bool fCloned;
1374 bool fInChar;
1375 bool fInCharCommentString;
1376 bool fInEnum;
1377 bool fInComment;
1378 bool fInString;
1379 bool fCheckMethods;
Cary Clarka560c472017-11-27 10:44:06 -05001380 bool fSkip = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001381 bool fWroteOut = false;
Cary Clark8032b982017-07-28 11:04:54 -04001382private:
1383 typedef ParserCommon INHERITED;
1384};
1385
1386class IncludeParser : public ParserCommon {
1387public:
1388 enum class IsStruct {
1389 kNo,
1390 kYes,
1391 };
1392
1393 IncludeParser() : ParserCommon()
1394 , fMaps {
1395 { nullptr, MarkType::kNone }
1396 , { nullptr, MarkType::kAnchor }
1397 , { nullptr, MarkType::kAlias }
1398 , { nullptr, MarkType::kBug }
1399 , { nullptr, MarkType::kClass }
1400 , { nullptr, MarkType::kCode }
1401 , { nullptr, MarkType::kColumn }
1402 , { nullptr, MarkType::kComment }
1403 , { nullptr, MarkType::kConst }
1404 , { &fIDefineMap, MarkType::kDefine }
1405 , { nullptr, MarkType::kDefinedBy }
1406 , { nullptr, MarkType::kDeprecated }
1407 , { nullptr, MarkType::kDescription }
1408 , { nullptr, MarkType::kDoxygen }
Cary Clarkac47b882018-01-11 10:35:44 -05001409 , { nullptr, MarkType::kDuration }
Cary Clark8032b982017-07-28 11:04:54 -04001410 , { &fIEnumMap, MarkType::kEnum }
1411 , { &fIEnumMap, MarkType::kEnumClass }
1412 , { nullptr, MarkType::kError }
1413 , { nullptr, MarkType::kExample }
1414 , { nullptr, MarkType::kExperimental }
1415 , { nullptr, MarkType::kExternal }
1416 , { nullptr, MarkType::kFile }
1417 , { nullptr, MarkType::kFormula }
1418 , { nullptr, MarkType::kFunction }
1419 , { nullptr, MarkType::kHeight }
1420 , { nullptr, MarkType::kImage }
1421 , { nullptr, MarkType::kLegend }
1422 , { nullptr, MarkType::kLink }
1423 , { nullptr, MarkType::kList }
Cary Clark154beea2017-10-26 07:58:48 -04001424 , { nullptr, MarkType::kLiteral }
Cary Clark8032b982017-07-28 11:04:54 -04001425 , { nullptr, MarkType::kMarkChar }
1426 , { nullptr, MarkType::kMember }
1427 , { nullptr, MarkType::kMethod }
1428 , { nullptr, MarkType::kNoExample }
Cary Clark154beea2017-10-26 07:58:48 -04001429 , { nullptr, MarkType::kOutdent }
Cary Clark8032b982017-07-28 11:04:54 -04001430 , { nullptr, MarkType::kParam }
1431 , { nullptr, MarkType::kPlatform }
1432 , { nullptr, MarkType::kPrivate }
1433 , { nullptr, MarkType::kReturn }
1434 , { nullptr, MarkType::kRoot }
1435 , { nullptr, MarkType::kRow }
1436 , { nullptr, MarkType::kSeeAlso }
Cary Clark61dfc3a2018-01-03 08:37:53 -05001437 , { nullptr, MarkType::kSet }
Cary Clark8032b982017-07-28 11:04:54 -04001438 , { nullptr, MarkType::kStdOut }
1439 , { &fIStructMap, MarkType::kStruct }
1440 , { nullptr, MarkType::kSubstitute }
1441 , { nullptr, MarkType::kSubtopic }
1442 , { nullptr, MarkType::kTable }
1443 , { &fITemplateMap, MarkType::kTemplate }
1444 , { nullptr, MarkType::kText }
1445 , { nullptr, MarkType::kTime }
1446 , { nullptr, MarkType::kToDo }
1447 , { nullptr, MarkType::kTopic }
1448 , { nullptr, MarkType::kTrack }
1449 , { &fITypedefMap, MarkType::kTypedef }
1450 , { &fIUnionMap, MarkType::kUnion }
1451 , { nullptr, MarkType::kVolatile }
1452 , { nullptr, MarkType::kWidth } }
1453 {
1454 this->reset();
1455 }
1456
1457 ~IncludeParser() override {}
1458
1459 void addKeyword(KeyWord keyWord);
1460
1461 void addPunctuation(Punctuation punctuation) {
1462 fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent);
1463 }
1464
1465 void addWord() {
1466 fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent);
1467 fIncludeWord = nullptr;
1468 }
1469
1470 void checkForMissingParams(const vector<string>& methodParams,
1471 const vector<string>& foundParams);
1472 bool checkForWord();
1473 string className() const;
1474 bool crossCheck(BmhParser& );
1475 IClassDefinition* defineClass(const Definition& includeDef, const string& className);
1476 void dumpClassTokens(IClassDefinition& classDef);
Cary Clark9174bda2017-09-19 17:39:32 -04001477 void dumpComment(const Definition& );
1478 void dumpEnum(const Definition& );
1479 void dumpMethod(const Definition& );
1480 void dumpMember(const Definition& );
Cary Clarkd0530ba2017-09-14 11:25:39 -04001481 bool dumpTokens(const string& directory);
Cary Clark9174bda2017-09-19 17:39:32 -04001482 bool dumpTokens(const string& directory, const string& skClassName);
Cary Clark8032b982017-07-28 11:04:54 -04001483 bool findComments(const Definition& includeDef, Definition* markupDef);
1484
1485 Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
1486 const string& typeName) {
1487 typedef Definition* DefinitionPtr;
1488 unordered_map<string, Definition>* map = fMaps[(int) markType].fInclude;
1489 if (!map) {
1490 return reportError<DefinitionPtr>("invalid mark type");
1491 }
1492 string name = this->uniqueName(*map, typeName);
1493 Definition& markupDef = (*map)[name];
1494 if (markupDef.fStart) {
1495 return reportError<DefinitionPtr>("definition already defined");
1496 }
1497 markupDef.fFileName = fFileName;
1498 markupDef.fStart = includeDef.fStart;
1499 markupDef.fContentStart = includeDef.fStart;
1500 markupDef.fName = name;
1501 markupDef.fContentEnd = includeDef.fContentEnd;
1502 markupDef.fTerminator = includeDef.fTerminator;
1503 markupDef.fParent = fParent;
1504 markupDef.fLineCount = includeDef.fLineCount;
1505 markupDef.fMarkType = markType;
1506 markupDef.fKeyWord = includeDef.fKeyWord;
1507 markupDef.fType = Definition::Type::kMark;
1508 return &markupDef;
1509 }
1510
1511 static KeyWord FindKey(const char* start, const char* end);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001512 bool internalName(const Definition& ) const;
Cary Clark8032b982017-07-28 11:04:54 -04001513 bool parseChar();
1514 bool parseComment(const string& filename, const char* start, const char* end, int lineCount,
1515 Definition* markupDef);
1516 bool parseClass(Definition* def, IsStruct);
1517 bool parseDefine();
1518 bool parseEnum(Definition* child, Definition* markupDef);
1519
1520 bool parseFromFile(const char* path) override {
Cary Clark2f466242017-12-11 16:03:17 -05001521 this->reset();
Cary Clark8032b982017-07-28 11:04:54 -04001522 if (!INHERITED::parseSetup(path)) {
1523 return false;
1524 }
1525 string name(path);
1526 return parseInclude(name);
1527 }
1528
1529 bool parseInclude(const string& name);
1530 bool parseMember(Definition* child, Definition* markupDef);
1531 bool parseMethod(Definition* child, Definition* markupDef);
1532 bool parseObject(Definition* child, Definition* markupDef);
1533 bool parseObjects(Definition* parent, Definition* markupDef);
1534 bool parseTemplate();
Cary Clark2f466242017-12-11 16:03:17 -05001535 bool parseTypedef(Definition* child, Definition* markupDef);
Cary Clark8032b982017-07-28 11:04:54 -04001536 bool parseUnion();
1537
1538 void popBracket() {
1539 SkASSERT(Definition::Type::kBracket == fParent->fType);
1540 this->popObject();
1541 Bracket bracket = this->topBracket();
1542 this->setBracketShortCuts(bracket);
1543 }
1544
1545 void pushBracket(Bracket bracket) {
1546 this->setBracketShortCuts(bracket);
1547 fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent);
1548 Definition* container = &fParent->fTokens.back();
1549 this->addDefinition(container);
1550 }
1551
1552 void reset() override {
1553 INHERITED::resetCommon();
1554 fRootTopic = nullptr;
1555 fInBrace = nullptr;
1556 fIncludeWord = nullptr;
Cary Clark73fa9722017-08-29 17:36:51 -04001557 fLastObject = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001558 fPrev = '\0';
1559 fInChar = false;
1560 fInCharCommentString = false;
1561 fInComment = false;
1562 fInEnum = false;
1563 fInFunction = false;
1564 fInString = false;
Cary Clarkf059e7c2017-12-20 14:53:21 -05001565 fFailed = false;
Cary Clark7cfcbca2018-01-04 16:11:51 -05001566 fPriorEnum = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001567 }
1568
1569 void setBracketShortCuts(Bracket bracket) {
1570 fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket;
1571 fInString = Bracket::kString == bracket;
1572 fInChar = Bracket::kChar == bracket;
1573 fInCharCommentString = fInChar || fInComment || fInString;
1574 }
1575
1576 Bracket topBracket() const {
1577 Definition* parent = fParent;
1578 while (parent && Definition::Type::kBracket != parent->fType) {
1579 parent = parent->fParent;
1580 }
1581 return parent ? parent->fBracket : Bracket::kNone;
1582 }
1583
1584 template <typename T>
1585 string uniqueName(const unordered_map<string, T>& m, const string& typeName) {
1586 string base(typeName.size() > 0 ? typeName : "_anonymous");
1587 string name(base);
1588 int anonCount = 1;
1589 do {
1590 auto iter = m.find(name);
1591 if (iter == m.end()) {
1592 return name;
1593 }
1594 name = base + '_';
1595 name += to_string(++anonCount);
1596 } while (true);
1597 // should never get here
1598 return string();
1599 }
1600
1601 void validate() const;
1602
Cary Clark9174bda2017-09-19 17:39:32 -04001603 void writeDefinition(const Definition& def) {
1604 if (def.length() > 1) {
1605 this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1606 this->lf(1);
1607 }
1608 }
1609
1610 void writeDefinition(const Definition& def, const string& name, int spaces) {
1611 this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1612 this->writeSpace(spaces);
1613 this->writeString(name);
1614 this->lf(1);
1615 }
1616
1617 void writeEndTag() {
1618 this->lf(1);
1619 this->writeString("##");
1620 this->lf(1);
1621 }
1622
1623 void writeEndTag(const char* tagType) {
1624 this->lf(1);
1625 this->writeString(string("#") + tagType + " ##");
1626 this->lf(1);
1627 }
1628
1629 void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) {
1630 this->lf(1);
1631 this->writeString(string("#") + tagType + " " + tagID);
1632 this->writeSpace(spaces);
1633 this->writeString("##");
1634 this->lf(1);
1635 }
1636
1637 void writeEndTag(const char* tagType, const string& tagID, int spaces = 1) {
1638 this->writeEndTag(tagType, tagID.c_str(), spaces);
1639 }
1640
Cary Clark154beea2017-10-26 07:58:48 -04001641 void writeIncompleteTag(const char* tagType, const string& tagID, int spaces = 1) {
1642 this->writeString(string("#") + tagType + " " + tagID);
1643 this->writeSpace(spaces);
1644 this->writeString("incomplete");
1645 this->writeSpace();
1646 this->writeString("##");
1647 this->lf(1);
1648 }
1649
1650 void writeIncompleteTag(const char* tagType) {
1651 this->writeString(string("#") + tagType + " incomplete ##");
1652 this->lf(1);
1653 }
1654
Cary Clark9174bda2017-09-19 17:39:32 -04001655 void writeTableHeader(const char* col1, size_t pad, const char* col2) {
1656 this->lf(1);
1657 this->writeString("#Table");
1658 this->lf(1);
1659 this->writeString("#Legend");
1660 this->lf(1);
1661 string legend = "# ";
1662 legend += col1;
1663 if (pad > strlen(col1)) {
1664 legend += string(pad - strlen(col1), ' ');
1665 }
1666 legend += " # ";
1667 legend += col2;
1668 legend += " ##";
1669 this->writeString(legend);
1670 this->lf(1);
1671 this->writeString("#Legend ##");
1672 this->lf(1);
1673 }
1674
1675 void writeTableRow(size_t pad, const string& col1) {
1676 this->lf(1);
1677 string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##";
1678 this->writeString(row);
1679 this->lf(1);
1680 }
1681
1682 void writeTableTrailer() {
1683 this->lf(1);
1684 this->writeString("#Table ##");
1685 this->lf(1);
1686 }
1687
1688 void writeTag(const char* tagType) {
1689 this->lf(1);
1690 this->writeString("#");
1691 this->writeString(tagType);
1692 }
1693
1694 void writeTagNoLF(const char* tagType, const char* tagID) {
1695 this->writeString("#");
1696 this->writeString(tagType);
1697 this->writeSpace();
1698 this->writeString(tagID);
1699 }
1700
1701 void writeTagNoLF(const char* tagType, const string& tagID) {
1702 this->writeTagNoLF(tagType, tagID.c_str());
1703 }
1704
1705 void writeTag(const char* tagType, const char* tagID) {
1706 this->lf(1);
1707 this->writeTagNoLF(tagType, tagID);
1708 }
1709
1710 void writeTag(const char* tagType, const string& tagID) {
1711 this->writeTag(tagType, tagID.c_str());
1712 }
1713
Cary Clark8032b982017-07-28 11:04:54 -04001714protected:
1715 static void ValidateKeyWords();
1716
1717 struct DefinitionMap {
1718 unordered_map<string, Definition>* fInclude;
1719 MarkType fMarkType;
1720 };
Ben Wagner63fd7602017-10-09 15:45:33 -04001721
Cary Clark8032b982017-07-28 11:04:54 -04001722 DefinitionMap fMaps[Last_MarkType + 1];
1723 unordered_map<string, Definition> fIncludeMap;
1724 unordered_map<string, IClassDefinition> fIClassMap;
1725 unordered_map<string, Definition> fIDefineMap;
1726 unordered_map<string, Definition> fIEnumMap;
Cary Clarka560c472017-11-27 10:44:06 -05001727 unordered_map<string, Definition> fIFunctionMap;
Cary Clark8032b982017-07-28 11:04:54 -04001728 unordered_map<string, Definition> fIStructMap;
1729 unordered_map<string, Definition> fITemplateMap;
1730 unordered_map<string, Definition> fITypedefMap;
1731 unordered_map<string, Definition> fIUnionMap;
1732 Definition* fRootTopic;
1733 Definition* fInBrace;
Cary Clark73fa9722017-08-29 17:36:51 -04001734 Definition* fLastObject;
Cary Clark7cfcbca2018-01-04 16:11:51 -05001735 Definition* fPriorEnum;
1736 int fPriorIndex;
Cary Clark8032b982017-07-28 11:04:54 -04001737 const char* fIncludeWord;
1738 char fPrev;
1739 bool fInChar;
1740 bool fInCharCommentString;
1741 bool fInComment;
1742 bool fInEnum;
1743 bool fInFunction;
1744 bool fInString;
Cary Clarkf059e7c2017-12-20 14:53:21 -05001745 bool fFailed;
Cary Clark8032b982017-07-28 11:04:54 -04001746
1747 typedef ParserCommon INHERITED;
1748};
1749
1750class IncludeWriter : public IncludeParser {
1751public:
1752 enum class Word {
1753 kStart,
1754 kCap,
1755 kFirst,
1756 kUnderline,
1757 kMixed,
1758 };
1759
Cary Clarkd0530ba2017-09-14 11:25:39 -04001760 enum class Phrase {
1761 kNo,
1762 kYes,
1763 };
1764
Cary Clark8032b982017-07-28 11:04:54 -04001765 enum class PunctuationState {
1766 kStart,
1767 kDelimiter,
1768 kPeriod,
Cary Clark1eace2d2017-07-31 07:52:43 -04001769 kSpace,
Cary Clark8032b982017-07-28 11:04:54 -04001770 };
1771
Cary Clarkce101242017-09-01 15:51:02 -04001772 enum class RefType {
1773 kUndefined,
1774 kNormal,
1775 kExternal,
1776 };
1777
Cary Clark8032b982017-07-28 11:04:54 -04001778 enum class Wrote {
1779 kNone,
1780 kLF,
1781 kChars,
1782 };
1783
Cary Clarkbad5ad72017-08-03 17:14:08 -04001784 struct IterState {
Ben Wagner63fd7602017-10-09 15:45:33 -04001785 IterState (list<Definition>::iterator tIter, list<Definition>::iterator tIterEnd)
Cary Clarkbad5ad72017-08-03 17:14:08 -04001786 : fDefIter(tIter)
1787 , fDefEnd(tIterEnd) {
1788 }
1789 list<Definition>::iterator fDefIter;
1790 list<Definition>::iterator fDefEnd;
1791 };
1792
Cary Clark73fa9722017-08-29 17:36:51 -04001793 struct ParentPair {
1794 const Definition* fParent;
1795 const ParentPair* fPrev;
1796 };
1797
Cary Clarkbef063a2017-10-31 15:44:45 -04001798 IncludeWriter() : IncludeParser() {
1799 this->reset();
1800 }
1801
Cary Clark8032b982017-07-28 11:04:54 -04001802 ~IncludeWriter() override {}
1803
1804 bool contentFree(int size, const char* data) const {
1805 while (size > 0 && data[0] <= ' ') {
1806 --size;
1807 ++data;
1808 }
1809 while (size > 0 && data[size - 1] <= ' ') {
1810 --size;
1811 }
1812 return 0 == size;
1813 }
1814
Cary Clark6fc50412017-09-21 12:31:06 -04001815 void descriptionOut(const Definition* def);
Cary Clark8032b982017-07-28 11:04:54 -04001816 void enumHeaderOut(const RootDefinition* root, const Definition& child);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001817 void enumMembersOut(const RootDefinition* root, Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001818 void enumSizeItems(const Definition& child);
1819 int lookupMethod(const PunctuationState punctuation, const Word word,
Ben Wagner63fd7602017-10-09 15:45:33 -04001820 const int start, const int run, int lastWrite,
Cary Clark6fc50412017-09-21 12:31:06 -04001821 const char* data, bool hasIndirection);
Cary Clark8032b982017-07-28 11:04:54 -04001822 int lookupReference(const PunctuationState punctuation, const Word word,
Ben Wagner63fd7602017-10-09 15:45:33 -04001823 const int start, const int run, int lastWrite, const char last,
Cary Clark8032b982017-07-28 11:04:54 -04001824 const char* data);
Cary Clark579985c2017-07-31 11:48:27 -04001825 void methodOut(const Definition* method, const Definition& child);
Cary Clark73fa9722017-08-29 17:36:51 -04001826 bool populate(Definition* def, ParentPair* parentPair, RootDefinition* root);
Cary Clark8032b982017-07-28 11:04:54 -04001827 bool populate(BmhParser& bmhParser);
1828
1829 void reset() override {
1830 INHERITED::resetCommon();
Cary Clark579985c2017-07-31 11:48:27 -04001831 fBmhMethod = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001832 fBmhParser = nullptr;
1833 fEnumDef = nullptr;
Cary Clark579985c2017-07-31 11:48:27 -04001834 fMethodDef = nullptr;
Cary Clark154beea2017-10-26 07:58:48 -04001835 fBmhStructDef = nullptr;
Cary Clark73fa9722017-08-29 17:36:51 -04001836 fAttrDeprecated = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001837 fInStruct = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001838 fWroteMethod = false;
Cary Clark154beea2017-10-26 07:58:48 -04001839 fIndentNext = false;
1840 fPendingMethod = false;
Cary Clark8032b982017-07-28 11:04:54 -04001841 }
1842
1843 string resolveMethod(const char* start, const char* end, bool first);
Cary Clarkce101242017-09-01 15:51:02 -04001844 string resolveRef(const char* start, const char* end, bool first, RefType* refType);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001845 Wrote rewriteBlock(int size, const char* data, Phrase phrase);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001846 Definition* structMemberOut(const Definition* memberStart, const Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001847 void structOut(const Definition* root, const Definition& child,
1848 const char* commentStart, const char* commentEnd);
Cary Clark884dd7d2017-10-11 10:37:52 -04001849 void structSizeMembers(const Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001850private:
1851 BmhParser* fBmhParser;
1852 Definition* fDeferComment;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001853 Definition* fLastComment;
Cary Clark579985c2017-07-31 11:48:27 -04001854 const Definition* fBmhMethod;
Cary Clark8032b982017-07-28 11:04:54 -04001855 const Definition* fEnumDef;
Cary Clark579985c2017-07-31 11:48:27 -04001856 const Definition* fMethodDef;
Cary Clark154beea2017-10-26 07:58:48 -04001857 const Definition* fBmhStructDef;
Cary Clark73fa9722017-08-29 17:36:51 -04001858 const Definition* fAttrDeprecated;
Cary Clark8032b982017-07-28 11:04:54 -04001859 const char* fContinuation; // used to construct paren-qualified method name
1860 int fAnonymousEnumCount;
1861 int fEnumItemValueTab;
1862 int fEnumItemCommentTab;
1863 int fStructMemberTab;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001864 int fStructValueTab;
Cary Clark8032b982017-07-28 11:04:54 -04001865 int fStructCommentTab;
1866 bool fInStruct;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001867 bool fWroteMethod;
Cary Clark154beea2017-10-26 07:58:48 -04001868 bool fIndentNext;
1869 bool fPendingMethod;
Cary Clark8032b982017-07-28 11:04:54 -04001870
1871 typedef IncludeParser INHERITED;
1872};
1873
Cary Clarkbef063a2017-10-31 15:44:45 -04001874class FiddleBase : public ParserCommon {
1875protected:
1876 FiddleBase(BmhParser* bmh) : ParserCommon()
1877 , fBmhParser(bmh)
1878 , fContinuation(false)
1879 , fTextOut(false)
1880 , fPngOut(false)
1881 {
Cary Clark8032b982017-07-28 11:04:54 -04001882 this->reset();
1883 }
1884
Cary Clarkbef063a2017-10-31 15:44:45 -04001885 void reset() override {
1886 INHERITED::resetCommon();
1887 }
1888
Cary Clark8032b982017-07-28 11:04:54 -04001889 Definition* findExample(const string& name) const;
Cary Clarkbef063a2017-10-31 15:44:45 -04001890 bool parseFiddles();
1891 virtual bool pngOut(Definition* example) = 0;
1892 virtual bool textOut(Definition* example, const char* stdOutStart,
1893 const char* stdOutEnd) = 0;
1894
1895 BmhParser* fBmhParser; // must be writable; writes example hash
1896 string fFullName;
1897 bool fContinuation;
1898 bool fTextOut;
1899 bool fPngOut;
1900private:
1901 typedef ParserCommon INHERITED;
1902};
1903
1904class FiddleParser : public FiddleBase {
1905public:
1906 FiddleParser(BmhParser* bmh) : FiddleBase(bmh) {
1907 fTextOut = true;
1908 }
Cary Clark8032b982017-07-28 11:04:54 -04001909
1910 bool parseFromFile(const char* path) override {
1911 if (!INHERITED::parseSetup(path)) {
1912 return false;
1913 }
1914 return parseFiddles();
1915 }
1916
Cary Clarkbef063a2017-10-31 15:44:45 -04001917private:
1918 bool pngOut(Definition* example) override {
1919 return true;
Cary Clark8032b982017-07-28 11:04:54 -04001920 }
1921
Cary Clarkbef063a2017-10-31 15:44:45 -04001922 bool textOut(Definition* example, const char* stdOutStart,
1923 const char* stdOutEnd) override;
1924
1925 typedef FiddleBase INHERITED;
1926};
1927
1928class Catalog : public FiddleBase {
1929public:
1930 Catalog(BmhParser* bmh) : FiddleBase(bmh) {}
1931
1932 bool appendFile(const string& path);
1933 bool closeCatalog();
1934 bool openCatalog(const char* inDir, const char* outDir);
Cary Clark2f466242017-12-11 16:03:17 -05001935 bool openStatus(const char* inDir, const char* outDir);
Cary Clarkbef063a2017-10-31 15:44:45 -04001936
1937 bool parseFromFile(const char* path) override ;
Cary Clark8032b982017-07-28 11:04:54 -04001938private:
Cary Clarkbef063a2017-10-31 15:44:45 -04001939 bool pngOut(Definition* example) override;
1940 bool textOut(Definition* example, const char* stdOutStart,
1941 const char* stdOutEnd) override;
Cary Clark8032b982017-07-28 11:04:54 -04001942
Cary Clarkbef063a2017-10-31 15:44:45 -04001943 string fDocsDir;
Cary Clark8032b982017-07-28 11:04:54 -04001944
Cary Clarkbef063a2017-10-31 15:44:45 -04001945 typedef FiddleBase INHERITED;
Cary Clark8032b982017-07-28 11:04:54 -04001946};
1947
1948class HackParser : public ParserCommon {
1949public:
1950 HackParser() : ParserCommon() {
1951 this->reset();
1952 }
1953
1954 bool parseFromFile(const char* path) override {
1955 if (!INHERITED::parseSetup(path)) {
1956 return false;
1957 }
1958 return hackFiles();
1959 }
1960
1961 void reset() override {
1962 INHERITED::resetCommon();
1963 }
1964
1965private:
1966 bool hackFiles();
1967
1968 typedef ParserCommon INHERITED;
1969};
1970
1971class MdOut : public ParserCommon {
1972public:
1973 MdOut(const BmhParser& bmh) : ParserCommon()
1974 , fBmhParser(bmh) {
1975 this->reset();
1976 }
1977
Cary Clark7cfcbca2018-01-04 16:11:51 -05001978 bool buildReferences(const char* docDir, const char* mdOutDirOrFile);
1979 bool buildStatus(const char* docDir, const char* mdOutDir);
Cary Clark8032b982017-07-28 11:04:54 -04001980private:
1981 enum class TableState {
1982 kNone,
1983 kRow,
1984 kColumn,
1985 };
1986
1987 string addReferences(const char* start, const char* end, BmhParser::Resolvable );
1988 bool buildRefFromFile(const char* fileName, const char* outDir);
Cary Clarka523d2d2017-08-30 08:58:10 -04001989 bool checkParamReturnBody(const Definition* def) const;
Cary Clark8032b982017-07-28 11:04:54 -04001990 void childrenOut(const Definition* def, const char* contentStart);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001991 const Definition* findParamType();
Cary Clark8032b982017-07-28 11:04:54 -04001992 const Definition* isDefined(const TextParser& parser, const string& ref, bool report) const;
1993 string linkName(const Definition* ) const;
1994 string linkRef(const string& leadingSpaces, const Definition*, const string& ref) const;
1995 void markTypeOut(Definition* );
Ben Wagner63fd7602017-10-09 15:45:33 -04001996 void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); }
Cary Clark8032b982017-07-28 11:04:54 -04001997 void mdHeaderOutLF(int depth, int lf);
1998 bool parseFromFile(const char* path) override {
1999 return true;
2000 }
2001
2002 void reset() override {
2003 INHERITED::resetCommon();
Cary Clarkbad5ad72017-08-03 17:14:08 -04002004 fEnumClass = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04002005 fMethod = nullptr;
2006 fRoot = nullptr;
Cary Clarkd0530ba2017-09-14 11:25:39 -04002007 fLastParam = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04002008 fTableState = TableState::kNone;
2009 fHasFiddle = false;
2010 fInDescription = false;
2011 fInList = false;
Cary Clarka560c472017-11-27 10:44:06 -05002012 fRespectLeadingSpace = false;
Cary Clark8032b982017-07-28 11:04:54 -04002013 }
2014
Cary Clark154beea2017-10-26 07:58:48 -04002015 BmhParser::Resolvable resolvable(const Definition* definition) const {
2016 MarkType markType = definition->fMarkType;
2017 if (MarkType::kCode == markType) {
2018 for (auto child : definition->fChildren) {
2019 if (MarkType::kLiteral == child->fMarkType) {
2020 return BmhParser::Resolvable::kLiteral;
2021 }
2022 }
2023 }
Ben Wagner63fd7602017-10-09 15:45:33 -04002024 if ((MarkType::kExample == markType
Cary Clark8032b982017-07-28 11:04:54 -04002025 || MarkType::kFunction == markType) && fHasFiddle) {
2026 return BmhParser::Resolvable::kNo;
2027 }
2028 return fBmhParser.fMaps[(int) markType].fResolve;
2029 }
2030
2031 void resolveOut(const char* start, const char* end, BmhParser::Resolvable );
2032
2033 const BmhParser& fBmhParser;
Cary Clarkbad5ad72017-08-03 17:14:08 -04002034 const Definition* fEnumClass;
Cary Clark8032b982017-07-28 11:04:54 -04002035 Definition* fMethod;
2036 RootDefinition* fRoot;
Cary Clarkd0530ba2017-09-14 11:25:39 -04002037 const Definition* fLastParam;
Cary Clark8032b982017-07-28 11:04:54 -04002038 TableState fTableState;
2039 bool fHasFiddle;
2040 bool fInDescription; // FIXME: for now, ignore unfound camelCase in description since it may
2041 // be defined in example which at present cannot be linked to
2042 bool fInList;
Cary Clarka560c472017-11-27 10:44:06 -05002043 bool fRespectLeadingSpace;
Cary Clark8032b982017-07-28 11:04:54 -04002044 typedef ParserCommon INHERITED;
2045};
2046
2047
2048// some methods cannot be trivially parsed; look for class-name / ~ / operator
2049class MethodParser : public TextParser {
2050public:
2051 MethodParser(const string& className, const string& fileName,
2052 const char* start, const char* end, int lineCount)
2053 : TextParser(fileName, start, end, lineCount)
2054 , fClassName(className) {
2055 }
2056
Cary Clark2f466242017-12-11 16:03:17 -05002057 ~MethodParser() override {}
2058
Cary Clark8032b982017-07-28 11:04:54 -04002059 void skipToMethodStart() {
2060 if (!fClassName.length()) {
2061 this->skipToAlphaNum();
2062 return;
2063 }
2064 while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
2065 this->next();
2066 }
2067 }
2068
2069 void skipToMethodEnd() {
2070 if (this->eof()) {
2071 return;
2072 }
2073 if (fClassName.length()) {
2074 if ('~' == this->peek()) {
2075 this->next();
2076 if (!this->startsWith(fClassName.c_str())) {
2077 --fChar;
2078 return;
2079 }
2080 }
2081 if (this->startsWith(fClassName.c_str()) || this->startsWith("operator")) {
Cary Clarka560c472017-11-27 10:44:06 -05002082 const char* ptr = this->anyOf("\n (");
Cary Clark8032b982017-07-28 11:04:54 -04002083 if (ptr && '(' == *ptr) {
2084 this->skipToEndBracket(')');
2085 SkAssertResult(')' == this->next());
Cary Clarka560c472017-11-27 10:44:06 -05002086 this->skipExact("_const");
Cary Clark8032b982017-07-28 11:04:54 -04002087 return;
2088 }
2089 }
2090 }
2091 if (this->startsWith("Sk") && this->wordEndsWith(".h")) { // allow include refs
2092 this->skipToNonAlphaNum();
2093 } else {
2094 this->skipFullName();
Cary Clarka560c472017-11-27 10:44:06 -05002095 if (this->endsWith("operator")) {
2096 const char* ptr = this->anyOf("\n (");
2097 if (ptr && '(' == *ptr) {
2098 this->skipToEndBracket(')');
2099 SkAssertResult(')' == this->next());
2100 this->skipExact("_const");
2101 }
2102 }
Cary Clark8032b982017-07-28 11:04:54 -04002103 }
2104 }
2105
2106 bool wordEndsWith(const char* str) const {
2107 const char* space = this->strnchr(' ', fEnd);
2108 if (!space) {
2109 return false;
2110 }
2111 size_t len = strlen(str);
2112 if (space < fChar + len) {
2113 return false;
2114 }
2115 return !strncmp(str, space - len, len);
2116 }
2117
2118private:
2119 string fClassName;
2120 typedef TextParser INHERITED;
2121};
2122
Cary Clarkac47b882018-01-11 10:35:44 -05002123bool SelfCheck(const BmhParser& );
2124
Cary Clark8032b982017-07-28 11:04:54 -04002125#endif