blob: c83927822a56d8ece5fc81196ba8dc9295fef0dc [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,
98 kEnum,
99 kEnumClass,
100 kError,
101 kExample,
102 kExperimental,
103 kExternal,
104 kFile,
105 kFormula,
106 kFunction,
107 kHeight,
108 kImage,
109 kLegend,
110 kLink,
111 kList,
Cary Clark154beea2017-10-26 07:58:48 -0400112 kLiteral, // don't lookup hyperlinks, do substitution, etc
Cary Clark8032b982017-07-28 11:04:54 -0400113 kMarkChar,
114 kMember,
115 kMethod,
116 kNoExample,
Cary Clark154beea2017-10-26 07:58:48 -0400117 kOutdent,
Cary Clark8032b982017-07-28 11:04:54 -0400118 kParam,
119 kPlatform,
120 kPrivate,
121 kReturn,
122 kRoot,
123 kRow,
124 kSeeAlso,
Cary Clark61dfc3a2018-01-03 08:37:53 -0500125 kSet,
Cary Clark8032b982017-07-28 11:04:54 -0400126 kStdOut,
127 kStruct,
128 kSubstitute,
129 kSubtopic,
130 kTable,
131 kTemplate,
132 kText,
133 kTime,
134 kToDo,
135 kTopic,
136 kTrack,
137 kTypedef,
138 kUnion,
139 kVolatile,
140 kWidth,
141};
142
143enum {
144 Last_MarkType = (int) MarkType::kWidth,
145};
146
147enum class Bracket {
148 kNone,
149 kParen,
150 kSquare,
151 kBrace,
152 kAngle,
153 kString,
154 kChar,
155 kSlashStar,
156 kSlashSlash,
157 kPound,
158 kColon,
Cary Clark73fa9722017-08-29 17:36:51 -0400159 kDebugCode, // parens get special treatment so SkDEBUGCODE( isn't treated as method
Cary Clark8032b982017-07-28 11:04:54 -0400160};
161
162enum class Punctuation { // catch-all for misc symbols tracked in C
163 kNone,
164 kAsterisk, // for pointer-to
165 kSemicolon, // e.g., to delinate xxx() const ; const int* yyy()
166 kLeftBrace,
167 kColon, // for foo() : bar(1), baz(2) {}
168};
169
Cary Clarkd0530ba2017-09-14 11:25:39 -0400170enum class KeyProperty {
171 kNone,
172 kClassSection,
173 kFunction,
174 kModifier,
175 kNumber,
176 kObject,
177 kPreprocessor,
178};
179
Cary Clark2f466242017-12-11 16:03:17 -0500180enum class StatusFilter {
181 kCompleted,
182 kInProgress,
183 kUnknown,
184};
185
Cary Clarkd0530ba2017-09-14 11:25:39 -0400186struct IncludeKey {
187 const char* fName;
188 KeyWord fKeyWord;
189 KeyProperty fProperty;
190};
191
192extern const IncludeKey kKeyWords[];
193
Cary Clark8032b982017-07-28 11:04:54 -0400194static inline bool has_nonwhitespace(const string& s) {
195 bool nonwhite = false;
196 for (const char& c : s) {
197 if (' ' < c) {
198 nonwhite = true;
199 break;
200 }
201 }
202 return nonwhite;
203}
204
205static inline void trim_end(string &s) {
206 s.erase(std::find_if(s.rbegin(), s.rend(),
207 std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
208}
209
210static inline void trim_end_spaces(string &s) {
211 while (s.length() > 0 && ' ' == s.back()) {
212 s.pop_back();
213 }
214}
215
216static inline void trim_start(string &s) {
217 s.erase(s.begin(), std::find_if(s.begin(), s.end(),
218 std::not1(std::ptr_fun<int, int>(std::isspace))));
219}
220
221static inline void trim_start_end(string& s) {
222 trim_start(s);
223 trim_end(s);
224}
225
226class NonAssignable {
227public:
228 NonAssignable(NonAssignable const&) = delete;
229 NonAssignable& operator=(NonAssignable const&) = delete;
230 NonAssignable() {}
231};
232
233class Definition;
234
235class TextParser : public NonAssignable {
236 TextParser() {} // only for ParserCommon to call
237 friend class ParserCommon;
238public:
Cary Clark2f466242017-12-11 16:03:17 -0500239 virtual ~TextParser() {}
Cary Clark8032b982017-07-28 11:04:54 -0400240 class Save {
241 public:
242 Save(TextParser* parser) {
243 fParser = parser;
244 fLine = parser->fLine;
245 fChar = parser->fChar;
246 fLineCount = parser->fLineCount;
247 }
248
249 void restore() const {
250 fParser->fLine = fLine;
251 fParser->fChar = fChar;
252 fParser->fLineCount = fLineCount;
253 }
254
255 private:
256 TextParser* fParser;
257 const char* fLine;
258 const char* fChar;
259 int fLineCount;
260 };
261
262 TextParser(const string& fileName, const char* start, const char* end, int lineCount)
263 : fFileName(fileName)
264 , fStart(start)
265 , fLine(start)
266 , fChar(start)
267 , fEnd(end)
268 , fLineCount(lineCount)
269 {
270 }
271
272 TextParser(const Definition* );
273
274 const char* anyOf(const char* str) const {
275 const char* ptr = fChar;
276 while (ptr < fEnd) {
277 if (strchr(str, ptr[0])) {
278 return ptr;
279 }
280 ++ptr;
281 }
282 return nullptr;
283 }
284
285 const char* anyOf(const char* wordStart, const char* wordList[], size_t wordListCount) const {
286 const char** wordPtr = wordList;
287 const char** wordEnd = wordPtr + wordListCount;
288 const size_t matchLen = fChar - wordStart;
289 while (wordPtr < wordEnd) {
290 const char* word = *wordPtr++;
291 if (strlen(word) == matchLen && !strncmp(wordStart, word, matchLen)) {
292 return word;
293 }
294 }
295 return nullptr;
296 }
297
298 char backup(const char* pattern) const {
299 size_t len = strlen(pattern);
300 const char* start = fChar - len;
301 if (start <= fStart) {
302 return '\0';
303 }
304 if (strncmp(start, pattern, len)) {
305 return '\0';
306 }
307 return start[-1];
308 }
309
310 bool contains(const char* match, const char* lineEnd, const char** loc) const {
311 *loc = this->strnstr(match, lineEnd);
312 return *loc;
313 }
314
Cary Clarka560c472017-11-27 10:44:06 -0500315 const char* doubleLF() const {
316 int count = 0;
317 const char* ptr = fChar;
318 const char* doubleStart = nullptr;
319 while (ptr < fEnd) {
320 if ('\n' == ptr[0]) {
321 if (++count == 1) {
322 doubleStart = ptr;
323 } else {
324 return doubleStart;
325 }
326 } else if (' ' < ptr[0]) {
327 count = 0;
328 }
329 ++ptr;
330 }
331 return nullptr;
332 }
333
334 bool endsWith(const char* match) {
335 int matchLen = strlen(match);
336 if (matchLen > fChar - fLine) {
337 return false;
338 }
339 return !strncmp(fChar - matchLen, match, matchLen);
340 }
341
Cary Clark8032b982017-07-28 11:04:54 -0400342 bool eof() const { return fChar >= fEnd; }
343
344 const char* lineEnd() const {
345 const char* ptr = fChar;
346 do {
347 if (ptr >= fEnd) {
348 return ptr;
349 }
350 char test = *ptr++;
351 if (test == '\n' || test == '\0') {
352 break;
353 }
354 } while (true);
355 return ptr;
356 }
357
358 ptrdiff_t lineLength() const {
359 return this->lineEnd() - fLine;
360 }
361
362 bool match(TextParser* );
363
Ben Wagner63fd7602017-10-09 15:45:33 -0400364 char next() {
Cary Clark8032b982017-07-28 11:04:54 -0400365 SkASSERT(fChar < fEnd);
366 char result = *fChar++;
367 if ('\n' == result) {
368 ++fLineCount;
369 fLine = fChar;
370 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400371 return result;
Cary Clark8032b982017-07-28 11:04:54 -0400372 }
373
374 char peek() const { SkASSERT(fChar < fEnd); return *fChar; }
375
376 void restorePlace(const TextParser& save) {
377 fChar = save.fChar;
378 fLine = save.fLine;
379 fLineCount = save.fLineCount;
380 }
381
382 void savePlace(TextParser* save) {
383 save->fChar = fChar;
384 save->fLine = fLine;
385 save->fLineCount = fLineCount;
386 }
387
388 void reportError(const char* errorStr) const;
389 void reportWarning(const char* errorStr) const;
390
391 template <typename T> T reportError(const char* errorStr) const {
392 this->reportError(errorStr);
393 return T();
394 }
395
396 bool sentenceEnd(const char* check) const {
397 while (check > fStart) {
398 --check;
399 if (' ' < check[0] && '.' != check[0]) {
400 return false;
401 }
402 if ('.' == check[0]) {
403 return ' ' >= check[1];
404 }
405 if ('\n' == check[0] && '\n' == check[1]) {
406 return true;
407 }
408 }
409 return true;
410 }
411
412 bool skipToEndBracket(char endBracket, const char* end = nullptr) {
413 if (nullptr == end) {
414 end = fEnd;
415 }
416 while (fChar[0] != endBracket) {
417 if (fChar >= end) {
418 return false;
419 }
420 (void) this->next();
421 }
422 return true;
423 }
424
425 bool skipToEndBracket(const char* endBracket) {
426 size_t len = strlen(endBracket);
427 while (strncmp(fChar, endBracket, len)) {
428 if (fChar >= fEnd) {
429 return false;
430 }
431 (void) this->next();
432 }
433 return true;
434 }
435
436 bool skipLine() {
437 return skipToEndBracket('\n');
438 }
439
440 void skipTo(const char* skip) {
441 while (fChar < skip) {
442 this->next();
443 }
444 }
445
446 void skipToAlpha() {
447 while (fChar < fEnd && !isalpha(fChar[0])) {
448 fChar++;
449 }
450 }
451
452 void skipToAlphaNum() {
453 while (fChar < fEnd && !isalnum(fChar[0])) {
454 fChar++;
455 }
456 }
457
458 bool skipExact(const char* pattern) {
459 if (!this->startsWith(pattern)) {
460 return false;
461 }
462 this->skipName(pattern);
463 return true;
464 }
465
466 // differs from skipToNonAlphaNum in that a.b isn't considered a full name,
467 // since a.b can't be found as a named definition
468 void skipFullName() {
469 while (fChar < fEnd && (isalnum(fChar[0])
Cary Clarka560c472017-11-27 10:44:06 -0500470 || '_' == fChar[0] /* || '-' == fChar[0] */
Cary Clark8032b982017-07-28 11:04:54 -0400471 || (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]))) {
472 if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
473 fChar++;
474 }
475 fChar++;
476 }
477 }
478
479 bool skipToLineStart() {
480 if (!this->skipLine()) {
481 return false;
482 }
483 if (!this->eof()) {
484 return this->skipWhiteSpace();
485 }
486 return true;
487 }
488
489 void skipToNonAlphaNum() {
490 while (fChar < fEnd && (isalnum(fChar[0])
491 || '_' == fChar[0] || '-' == fChar[0]
Cary Clarkce101242017-09-01 15:51:02 -0400492 || (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
Cary Clark8032b982017-07-28 11:04:54 -0400493 || ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
494 if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
495 fChar++;
496 }
497 fChar++;
498 }
499 }
500
501 void skipToSpace() {
502 while (fChar < fEnd && ' ' != fChar[0]) {
503 fChar++;
504 }
505 }
506
Cary Clarka560c472017-11-27 10:44:06 -0500507 void skipToWhiteSpace() {
508 while (fChar < fEnd && ' ' < fChar[0]) {
509 fChar++;
510 }
511 }
512
Cary Clark8032b982017-07-28 11:04:54 -0400513 bool skipName(const char* word) {
514 size_t len = strlen(word);
Cary Clarkce101242017-09-01 15:51:02 -0400515 if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
Cary Clarkd0530ba2017-09-14 11:25:39 -0400516 for (size_t i = 0; i < len; ++i) {
517 this->next();
518 }
Cary Clark8032b982017-07-28 11:04:54 -0400519 }
520 return this->eof() || ' ' >= fChar[0];
521 }
522
Ben Wagner63fd7602017-10-09 15:45:33 -0400523 bool skipSpace() {
524 while (' ' == this->peek()) {
Cary Clark8032b982017-07-28 11:04:54 -0400525 (void) this->next();
526 if (fChar >= fEnd) {
527 return false;
528 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400529 }
530 return true;
Cary Clark8032b982017-07-28 11:04:54 -0400531 }
532
533 bool skipWord(const char* word) {
534 if (!this->skipWhiteSpace()) {
535 return false;
536 }
537 const char* save = fChar;
538 if (!this->skipName(word)) {
539 fChar = save;
540 return false;
541 }
542 if (!this->skipWhiteSpace()) {
543 return false;
544 }
545 return true;
546 }
547
Ben Wagner63fd7602017-10-09 15:45:33 -0400548 bool skipWhiteSpace() {
549 while (' ' >= this->peek()) {
Cary Clark8032b982017-07-28 11:04:54 -0400550 (void) this->next();
551 if (fChar >= fEnd) {
552 return false;
553 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400554 }
555 return true;
Cary Clark8032b982017-07-28 11:04:54 -0400556 }
557
558 bool startsWith(const char* str) const {
559 size_t len = strlen(str);
Ben Wagner63fd7602017-10-09 15:45:33 -0400560 ptrdiff_t lineLen = fEnd - fChar;
Cary Clark8032b982017-07-28 11:04:54 -0400561 return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
562 }
563
Cary Clarkbad5ad72017-08-03 17:14:08 -0400564 // ignores minor white space differences
565 bool startsWith(const char* str, size_t oLen) const {
566 size_t tIndex = 0;
567 size_t tLen = fEnd - fChar;
568 size_t oIndex = 0;
569 while (oIndex < oLen && tIndex < tLen) {
570 bool tSpace = ' ' >= fChar[tIndex];
571 bool oSpace = ' ' >= str[oIndex];
572 if (tSpace != oSpace) {
573 break;
574 }
575 if (tSpace) {
576 do {
577 ++tIndex;
578 } while (tIndex < tLen && ' ' >= fChar[tIndex]);
579 do {
580 ++oIndex;
581 } while (oIndex < oLen && ' ' >= str[oIndex]);
582 continue;
583 }
584 if (fChar[tIndex] != str[oIndex]) {
585 break;
586 }
587 ++tIndex;
588 ++oIndex;
589 }
590 return oIndex >= oLen;
591 }
592
Cary Clark8032b982017-07-28 11:04:54 -0400593 const char* strnchr(char ch, const char* end) const {
594 const char* ptr = fChar;
595 while (ptr < end) {
596 if (ptr[0] == ch) {
597 return ptr;
598 }
599 ++ptr;
600 }
601 return nullptr;
602 }
603
604 const char* strnstr(const char *match, const char* end) const {
605 size_t matchLen = strlen(match);
606 SkASSERT(matchLen > 0);
607 ptrdiff_t len = end - fChar;
608 SkASSERT(len >= 0);
609 if ((size_t) len < matchLen ) {
610 return nullptr;
611 }
612 size_t count = len - matchLen;
613 for (size_t index = 0; index <= count; index++) {
614 if (0 == strncmp(&fChar[index], match, matchLen)) {
615 return &fChar[index];
616 }
617 }
618 return nullptr;
619 }
620
Cary Clarkce101242017-09-01 15:51:02 -0400621 const char* trimmedBracketEnd(const char bracket) const {
622 int max = (int) (this->lineLength());
Cary Clark8032b982017-07-28 11:04:54 -0400623 int index = 0;
624 while (index < max && bracket != fChar[index]) {
625 ++index;
626 }
627 SkASSERT(index < max);
628 while (index > 0 && ' ' >= fChar[index - 1]) {
629 --index;
630 }
631 return fChar + index;
632 }
633
634 const char* trimmedLineEnd() const {
635 const char* result = this->lineEnd();
636 while (result > fChar && ' ' >= result[-1]) {
637 --result;
638 }
639 return result;
640 }
641
642 void trimEnd() {
643 while (fEnd > fStart && ' ' >= fEnd[-1]) {
644 --fEnd;
645 }
646 }
647
Cary Clark2f466242017-12-11 16:03:17 -0500648 // FIXME: nothing else in TextParser knows from C++ --
649 // there could be a class between TextParser and ParserCommon
650 virtual string typedefName();
651
Cary Clark8032b982017-07-28 11:04:54 -0400652 const char* wordEnd() const {
653 const char* end = fChar;
654 while (isalnum(end[0]) || '_' == end[0] || '-' == end[0]) {
655 ++end;
656 }
657 return end;
658 }
659
660 string fFileName;
661 const char* fStart;
662 const char* fLine;
663 const char* fChar;
664 const char* fEnd;
665 size_t fLineCount;
666};
667
668class EscapeParser : public TextParser {
669public:
670 EscapeParser(const char* start, const char* end) :
671 TextParser("", start, end, 0) {
672 const char* reader = fStart;
673 fStorage = new char[end - start];
674 char* writer = fStorage;
675 while (reader < fEnd) {
676 char ch = *reader++;
677 if (ch != '\\') {
678 *writer++ = ch;
679 } else {
680 char ctrl = *reader++;
681 if (ctrl == 'u') {
682 unsigned unicode = 0;
683 for (int i = 0; i < 4; ++i) {
684 unicode <<= 4;
685 SkASSERT((reader[0] >= '0' && reader[0] <= '9') ||
Cary Clarka560c472017-11-27 10:44:06 -0500686 (reader[0] >= 'A' && reader[0] <= 'F') ||
687 (reader[0] >= 'a' && reader[0] <= 'f'));
Cary Clark8032b982017-07-28 11:04:54 -0400688 int nibble = *reader++ - '0';
689 if (nibble > 9) {
Cary Clarka560c472017-11-27 10:44:06 -0500690 nibble = (nibble & ~('a' - 'A')) - 'A' + '9' + 1;
Cary Clark8032b982017-07-28 11:04:54 -0400691 }
692 unicode |= nibble;
693 }
694 SkASSERT(unicode < 256);
695 *writer++ = (unsigned char) unicode;
696 } else {
697 SkASSERT(ctrl == 'n');
698 *writer++ = '\n';
699 }
700 }
701 }
702 fStart = fLine = fChar = fStorage;
703 fEnd = writer;
704 }
705
Cary Clark2f466242017-12-11 16:03:17 -0500706 ~EscapeParser() override {
Cary Clark8032b982017-07-28 11:04:54 -0400707 delete fStorage;
708 }
709private:
710 char* fStorage;
711};
712
713class RootDefinition;
714
715class Definition : public NonAssignable {
716public:
717 enum Type {
718 kNone,
719 kWord,
720 kMark,
721 kKeyWord,
722 kBracket,
723 kPunctuation,
724 kFileType,
725 };
726
727 enum class TrimExtract {
728 kNo,
729 kYes
730 };
731
Cary Clarkbef063a2017-10-31 15:44:45 -0400732 enum class ExampleOptions {
733 kText,
734 kPng,
735 kAll
736 };
737
Cary Clark8032b982017-07-28 11:04:54 -0400738 enum class MethodType {
739 kNone,
740 kConstructor,
741 kDestructor,
742 kOperator,
743 };
744
Cary Clarka560c472017-11-27 10:44:06 -0500745 enum class Operator {
746 kUnknown,
747 kAdd,
748 kAddTo,
749 kArray,
750 kCast,
751 kCopy,
752 kDelete,
753 kDereference,
754 kEqual,
755 kMinus,
756 kMove,
757 kMultiply,
758 kMultiplyBy,
759 kNew,
760 kNotEqual,
761 kSubtract,
762 kSubtractFrom,
763 };
764
Cary Clark8032b982017-07-28 11:04:54 -0400765 Definition() {}
766
Ben Wagner63fd7602017-10-09 15:45:33 -0400767 Definition(const char* start, const char* end, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400768 : fStart(start)
769 , fContentStart(start)
770 , fContentEnd(end)
771 , fParent(parent)
772 , fLineCount(line)
773 , fType(Type::kWord) {
774 if (parent) {
775 SkASSERT(parent->fFileName.length() > 0);
776 fFileName = parent->fFileName;
777 }
778 this->setParentIndex();
779 }
780
Ben Wagner63fd7602017-10-09 15:45:33 -0400781 Definition(MarkType markType, const char* start, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400782 : Definition(markType, start, nullptr, line, parent) {
783 }
784
Ben Wagner63fd7602017-10-09 15:45:33 -0400785 Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400786 : Definition(start, end, line, parent) {
787 fMarkType = markType;
Ben Wagner63fd7602017-10-09 15:45:33 -0400788 fType = Type::kMark;
Cary Clark8032b982017-07-28 11:04:54 -0400789 }
790
Ben Wagner63fd7602017-10-09 15:45:33 -0400791 Definition(Bracket bracket, const char* start, int lineCount, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400792 : Definition(start, nullptr, lineCount, parent) {
793 fBracket = bracket;
794 fType = Type::kBracket;
795 }
796
Ben Wagner63fd7602017-10-09 15:45:33 -0400797 Definition(KeyWord keyWord, const char* start, const char* end, int lineCount,
798 Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400799 : Definition(start, end, lineCount, parent) {
800 fKeyWord = keyWord;
801 fType = Type::kKeyWord;
802 }
803
Ben Wagner63fd7602017-10-09 15:45:33 -0400804 Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent)
Cary Clark8032b982017-07-28 11:04:54 -0400805 : Definition(start, nullptr, lineCount, parent) {
806 fPunctuation = punctuation;
807 fType = Type::kPunctuation;
808 }
809
810 virtual ~Definition() {}
811
812 virtual RootDefinition* asRoot() { SkASSERT(0); return nullptr; }
813 virtual const RootDefinition* asRoot() const { SkASSERT(0); return nullptr; }
Cary Clarka560c472017-11-27 10:44:06 -0500814 bool boilerplateIfDef(Definition* parent);
815 bool boilerplateDef(Definition* parent);
Cary Clark8032b982017-07-28 11:04:54 -0400816
817 bool boilerplateEndIf() {
818 return true;
819 }
820
821 bool checkMethod() const;
Cary Clark73fa9722017-08-29 17:36:51 -0400822 bool crossCheck2(const Definition& includeToken) const;
Cary Clark8032b982017-07-28 11:04:54 -0400823 bool crossCheck(const Definition& includeToken) const;
824 bool crossCheckInside(const char* start, const char* end, const Definition& includeToken) const;
Cary Clarkbef063a2017-10-31 15:44:45 -0400825 bool exampleToScript(string* result, ExampleOptions ) const;
Cary Clarka560c472017-11-27 10:44:06 -0500826 string extractText(TrimExtract trimExtract) const;
Cary Clark8032b982017-07-28 11:04:54 -0400827 string fiddleName() const;
828 string formatFunction() const;
829 const Definition* hasChild(MarkType markType) const;
830 const Definition* hasParam(const string& ref) const;
831 bool isClone() const { return fClone; }
832
833 Definition* iRootParent() {
834 Definition* test = fParent;
835 while (test) {
836 if (Type::kKeyWord == test->fType && KeyWord::kClass == test->fKeyWord) {
837 return test;
838 }
839 test = test->fParent;
840 }
841 return nullptr;
842 }
843
844 virtual bool isRoot() const { return false; }
845
846 int length() const {
847 return (int) (fContentEnd - fContentStart);
848 }
849
850 bool methodHasReturn(const string& name, TextParser* methodParser) const;
851 string methodName() const;
Ben Wagner63fd7602017-10-09 15:45:33 -0400852 bool nextMethodParam(TextParser* methodParser, const char** nextEndPtr,
Cary Clark8032b982017-07-28 11:04:54 -0400853 string* paramName) const;
Cary Clarka560c472017-11-27 10:44:06 -0500854 static string NormalizedName(string name);
Cary Clark8032b982017-07-28 11:04:54 -0400855 bool paramsMatch(const string& fullRef, const string& name) const;
Cary Clarka560c472017-11-27 10:44:06 -0500856 bool parseOperator(size_t doubleColons, string& result);
Cary Clark8032b982017-07-28 11:04:54 -0400857
858 string printableName() const {
859 string result(fName);
860 std::replace(result.begin(), result.end(), '_', ' ');
861 return result;
862 }
863
Cary Clark9174bda2017-09-19 17:39:32 -0400864 template <typename T> T reportError(const char* errorStr) const {
865 TextParser tp(this);
866 tp.reportError(errorStr);
867 return T();
868 }
869
Cary Clark8032b982017-07-28 11:04:54 -0400870 virtual RootDefinition* rootParent() { SkASSERT(0); return nullptr; }
Cary Clarka560c472017-11-27 10:44:06 -0500871 void setCanonicalFiddle();
Cary Clark8032b982017-07-28 11:04:54 -0400872
873 void setParentIndex() {
874 fParentIndex = fParent ? (int) fParent->fTokens.size() : -1;
875 }
876
Cary Clarka560c472017-11-27 10:44:06 -0500877 void setWrapper();
878
Cary Clark8032b982017-07-28 11:04:54 -0400879 string fText; // if text is constructed instead of in a file, it's put here
880 const char* fStart = nullptr; // .. in original text file, or the start of fText
881 const char* fContentStart; // start past optional markup name
882 string fName;
883 string fFiddle; // if its a constructor or operator, fiddle name goes here
884 const char* fContentEnd = nullptr; // the end of the contained text
885 const char* fTerminator = nullptr; // the end of the markup, normally ##\n or \n
886 Definition* fParent = nullptr;
887 list<Definition> fTokens;
888 vector<Definition*> fChildren;
889 string fHash; // generated by fiddle
890 string fFileName;
Cary Clarka560c472017-11-27 10:44:06 -0500891 mutable string fWrapper; // used by Example to wrap into proper function
Cary Clark8032b982017-07-28 11:04:54 -0400892 size_t fLineCount = 0;
893 int fParentIndex = 0;
894 MarkType fMarkType = MarkType::kNone;
895 KeyWord fKeyWord = KeyWord::kNone;
896 Bracket fBracket = Bracket::kNone;
897 Punctuation fPunctuation = Punctuation::kNone;
898 MethodType fMethodType = MethodType::kNone;
Cary Clarka560c472017-11-27 10:44:06 -0500899 Operator fOperator = Operator::kUnknown;
Cary Clark8032b982017-07-28 11:04:54 -0400900 Type fType = Type::kNone;
901 bool fClone = false;
902 bool fCloned = false;
Cary Clarka560c472017-11-27 10:44:06 -0500903 bool fOperatorConst = false;
Cary Clark8032b982017-07-28 11:04:54 -0400904 bool fPrivate = false;
905 bool fShort = false;
906 bool fMemberStart = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -0400907 bool fAnonymous = false;
Cary Clark8032b982017-07-28 11:04:54 -0400908 mutable bool fVisited = false;
909};
910
911class RootDefinition : public Definition {
912public:
Cary Clarkce101242017-09-01 15:51:02 -0400913 enum class AllowParens {
914 kNo,
915 kYes,
916 };
917
Cary Clark8032b982017-07-28 11:04:54 -0400918 RootDefinition() {
919 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400920
Cary Clark8032b982017-07-28 11:04:54 -0400921 RootDefinition(MarkType markType, const char* start, int line, Definition* parent)
922 : Definition(markType, start, line, parent) {
923 }
924
Ben Wagner63fd7602017-10-09 15:45:33 -0400925 RootDefinition(MarkType markType, const char* start, const char* end, int line,
Cary Clark8032b982017-07-28 11:04:54 -0400926 Definition* parent) : Definition(markType, start, end, line, parent) {
927 }
928
929 ~RootDefinition() override {
930 for (auto& iter : fBranches) {
931 delete iter.second;
932 }
933 }
934
935 RootDefinition* asRoot() override { return this; }
936 const RootDefinition* asRoot() const override { return this; }
937 void clearVisited();
Cary Clarkf5404bb2018-01-05 12:10:09 -0500938 bool dumpUnVisited();
Cary Clarkce101242017-09-01 15:51:02 -0400939 const Definition* find(const string& ref, AllowParens ) const;
Cary Clark8032b982017-07-28 11:04:54 -0400940 bool isRoot() const override { return true; }
941 RootDefinition* rootParent() override { return fRootParent; }
942 void setRootParent(RootDefinition* rootParent) { fRootParent = rootParent; }
943
944 unordered_map<string, RootDefinition*> fBranches;
945 unordered_map<string, Definition> fLeaves;
946private:
947 RootDefinition* fRootParent = nullptr;
948};
949
950struct IClassDefinition : public Definition {
951 unordered_map<string, Definition*> fEnums;
952 unordered_map<string, Definition*> fMembers;
953 unordered_map<string, Definition*> fMethods;
954 unordered_map<string, Definition*> fStructs;
Cary Clark2f466242017-12-11 16:03:17 -0500955 unordered_map<string, Definition*> fTypedefs;
Cary Clark8032b982017-07-28 11:04:54 -0400956};
957
958struct Reference {
959 Reference()
960 : fLocation(nullptr)
961 , fDefinition(nullptr) {
962 }
963
964 const char* fLocation; // .. in original text file
965 const Definition* fDefinition;
966};
967
968struct TypeNames {
969 const char* fName;
970 MarkType fMarkType;
971};
972
973class ParserCommon : public TextParser {
974public:
975
976 ParserCommon() : TextParser()
977 , fParent(nullptr)
Cary Clarkd0530ba2017-09-14 11:25:39 -0400978 , fDebugOut(false)
Cary Clark8032b982017-07-28 11:04:54 -0400979 {
980 }
981
Cary Clark2f466242017-12-11 16:03:17 -0500982 ~ParserCommon() override {
Cary Clark8032b982017-07-28 11:04:54 -0400983 }
984
985 void addDefinition(Definition* def) {
986 fParent->fChildren.push_back(def);
987 fParent = def;
988 }
989
990 void indentToColumn(int column) {
991 SkASSERT(column >= fColumn);
Cary Clarkd0530ba2017-09-14 11:25:39 -0400992 if (fDebugOut) {
993 SkDebugf("%*s", column - fColumn, "");
994 }
Cary Clark8032b982017-07-28 11:04:54 -0400995 fprintf(fOut, "%*s", column - fColumn, "");
996 fColumn = column;
997 fSpaces += column - fColumn;
998 }
999
1000 bool leadingPunctuation(const char* str, size_t len) const {
1001 if (!fPendingSpace) {
1002 return false;
1003 }
1004 if (len < 2) {
1005 return false;
1006 }
1007 if ('.' != str[0] && ',' != str[0] && ';' != str[0] && ':' != str[0]) {
1008 return false;
1009 }
1010 return ' ' >= str[1];
1011 }
1012
1013 void lf(int count) {
1014 fPendingLF = SkTMax(fPendingLF, count);
1015 this->nl();
1016 }
1017
1018 void lfAlways(int count) {
1019 this->lf(count);
1020 this->writePending();
1021 }
1022
1023 void lfcr() {
1024 this->lf(1);
1025 }
1026
1027 void nl() {
1028 fLinefeeds = 0;
1029 fSpaces = 0;
1030 fColumn = 0;
Cary Clark9174bda2017-09-19 17:39:32 -04001031 fPendingSpace = 0;
Cary Clark8032b982017-07-28 11:04:54 -04001032 }
1033
1034 bool parseFile(const char* file, const char* suffix);
Cary Clark2f466242017-12-11 16:03:17 -05001035 bool parseStatus(const char* file, const char* suffix, StatusFilter filter);
Cary Clark8032b982017-07-28 11:04:54 -04001036 virtual bool parseFromFile(const char* path) = 0;
1037 bool parseSetup(const char* path);
1038
1039 void popObject() {
1040 fParent->fContentEnd = fParent->fTerminator = fChar;
1041 fParent = fParent->fParent;
1042 }
1043
Cary Clark7cfcbca2018-01-04 16:11:51 -05001044 const char* ReadToBuffer(string filename, int* size);
1045
Cary Clark8032b982017-07-28 11:04:54 -04001046 virtual void reset() = 0;
1047
1048 void resetCommon() {
1049 fLine = fChar = fStart;
1050 fLineCount = 0;
1051 fParent = nullptr;
1052 fIndent = 0;
1053 fOut = nullptr;
1054 fMaxLF = 2;
1055 fPendingLF = 0;
Cary Clark9174bda2017-09-19 17:39:32 -04001056 fPendingSpace = 0;
Cary Clark154beea2017-10-26 07:58:48 -04001057 fOutdentNext = false;
Cary Clark8032b982017-07-28 11:04:54 -04001058 nl();
1059 }
1060
1061 void setAsParent(Definition* definition) {
1062 if (fParent) {
1063 fParent->fChildren.push_back(definition);
1064 definition->fParent = fParent;
1065 }
1066 fParent = definition;
1067 }
1068
1069 void singleLF() {
1070 fMaxLF = 1;
1071 }
1072
Cary Clark8032b982017-07-28 11:04:54 -04001073 void writeBlock(int size, const char* data) {
1074 SkAssertResult(writeBlockTrim(size, data));
1075 }
Cary Clark154beea2017-10-26 07:58:48 -04001076
1077 void writeBlockIndent(int size, const char* data);
1078 bool writeBlockTrim(int size, const char* data);
1079
Cary Clark8032b982017-07-28 11:04:54 -04001080 void writeCommentHeader() {
1081 this->lf(2);
1082 this->writeString("/**");
1083 this->writeSpace();
1084 }
1085
1086 void writeCommentTrailer() {
1087 this->writeString("*/");
1088 this->lfcr();
1089 }
1090
Cary Clark154beea2017-10-26 07:58:48 -04001091 void writePending();
1092
Cary Clark8032b982017-07-28 11:04:54 -04001093 // write a pending space, so that two consecutive calls
1094 // don't double write, and trailing spaces on lines aren't written
Cary Clark9174bda2017-09-19 17:39:32 -04001095 void writeSpace(int count = 1) {
Cary Clark8032b982017-07-28 11:04:54 -04001096 SkASSERT(!fPendingLF);
1097 SkASSERT(!fLinefeeds);
1098 SkASSERT(fColumn > 0);
1099 SkASSERT(!fSpaces);
Cary Clark9174bda2017-09-19 17:39:32 -04001100 fPendingSpace = count;
Cary Clark8032b982017-07-28 11:04:54 -04001101 }
1102
Cary Clark154beea2017-10-26 07:58:48 -04001103 void writeString(const char* str);
Cary Clark8032b982017-07-28 11:04:54 -04001104
Cary Clark9174bda2017-09-19 17:39:32 -04001105 void writeString(const string& str) {
1106 this->writeString(str.c_str());
1107 }
1108
Cary Clark7cfcbca2018-01-04 16:11:51 -05001109 bool writtenFileDiffers(string filename, string readname);
Cary Clark8032b982017-07-28 11:04:54 -04001110
1111 unordered_map<string, sk_sp<SkData>> fRawData;
1112 unordered_map<string, vector<char>> fLFOnly;
1113 Definition* fParent;
1114 FILE* fOut;
1115 int fLinefeeds; // number of linefeeds last written, zeroed on non-space
Cary Clark9174bda2017-09-19 17:39:32 -04001116 int fMaxLF; // number of linefeeds allowed
1117 int fPendingLF; // number of linefeeds to write (can be suppressed)
1118 int fSpaces; // number of spaces (indent) last written, zeroed on non-space
1119 int fColumn; // current column; number of chars past last linefeed
1120 int fIndent; // desired indention
1121 int fPendingSpace; // one or two spaces should preceed the next string or block
1122 char fLastChar; // last written
1123 bool fDebugOut; // set true to write to std out
Cary Clark154beea2017-10-26 07:58:48 -04001124 bool fOutdentNext; // set at end of embedded struct to prevent premature outdent
Cary Clark8032b982017-07-28 11:04:54 -04001125private:
1126 typedef TextParser INHERITED;
1127};
1128
Cary Clark2f466242017-12-11 16:03:17 -05001129struct JsonStatus {
1130 const Json::Value& fObject;
1131 Json::Value::iterator fIter;
1132 string fName;
1133};
Cary Clark8032b982017-07-28 11:04:54 -04001134
Cary Clark2f466242017-12-11 16:03:17 -05001135class StatusIter : public ParserCommon {
1136public:
1137 StatusIter(const char* statusFile, const char* suffix, StatusFilter);
1138 ~StatusIter() override {}
1139 string baseDir();
1140 bool empty() { return fStack.empty(); }
1141 bool next(string* file);
1142protected:
1143 bool parseFromFile(const char* path) override;
1144 void reset() override;
1145private:
1146 vector<JsonStatus> fStack;
1147 Json::Value fRoot;
1148 const char* fSuffix;
1149 StatusFilter fFilter;
1150};
Cary Clark8032b982017-07-28 11:04:54 -04001151
1152class BmhParser : public ParserCommon {
1153public:
1154 enum class MarkLookup {
1155 kRequire,
1156 kAllowUnknown,
1157 };
1158
1159 enum class Resolvable {
1160 kNo, // neither resolved nor output
1161 kYes, // resolved, output
1162 kOut, // not resolved, but output
Cary Clark154beea2017-10-26 07:58:48 -04001163 kLiteral, // output untouched (FIXME: is this really different from kOut?)
Cary Clark8032b982017-07-28 11:04:54 -04001164 };
1165
1166 enum class Exemplary {
1167 kNo,
1168 kYes,
1169 kOptional,
1170 };
1171
Cary Clarkce101242017-09-01 15:51:02 -04001172 enum class TableState {
1173 kNone,
1174 kColumnStart,
1175 kColumnEnd,
1176 };
1177
Cary Clark8032b982017-07-28 11:04:54 -04001178#define M(mt) (1LL << (int) MarkType::k##mt)
1179#define M_D M(Description)
1180#define M_CS M(Class) | M(Struct)
1181#define M_ST M(Subtopic) | M(Topic)
1182#define M_CSST M_CS | M_ST
1183#ifdef M_E
1184#undef M_E
1185#endif
1186#define M_E M(Enum) | M(EnumClass)
1187
1188#define R_Y Resolvable::kYes
1189#define R_N Resolvable::kNo
1190#define R_O Resolvable::kOut
1191
1192#define E_Y Exemplary::kYes
1193#define E_N Exemplary::kNo
1194#define E_O Exemplary::kOptional
1195
Cary Clarka560c472017-11-27 10:44:06 -05001196 BmhParser(bool skip) : ParserCommon()
Ben Wagner63fd7602017-10-09 15:45:33 -04001197 , fMaps {
Cary Clark8032b982017-07-28 11:04:54 -04001198// names without formal definitions (e.g. Column) aren't included
1199// fill in other names once they're actually used
Cary Clarkce101242017-09-01 15:51:02 -04001200 { "", nullptr, MarkType::kNone, R_Y, E_N, 0 }
Cary Clark7cfcbca2018-01-04 16:11:51 -05001201, { "A", nullptr, MarkType::kAnchor, R_N, E_N, 0 }
Cary Clarkce101242017-09-01 15:51:02 -04001202, { "Alias", nullptr, MarkType::kAlias, R_N, E_N, 0 }
1203, { "Bug", nullptr, MarkType::kBug, R_N, E_N, 0 }
1204, { "Class", &fClassMap, MarkType::kClass, R_Y, E_O, M_CSST | M(Root) }
Cary Clark154beea2017-10-26 07:58:48 -04001205, { "Code", nullptr, MarkType::kCode, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clarkce101242017-09-01 15:51:02 -04001206, { "", nullptr, MarkType::kColumn, R_Y, E_N, M(Row) }
1207, { "", nullptr, MarkType::kComment, R_N, E_N, 0 }
1208, { "Const", &fConstMap, MarkType::kConst, R_Y, E_N, M_E | M_ST }
1209, { "Define", nullptr, MarkType::kDefine, R_O, E_N, M_ST }
1210, { "DefinedBy", nullptr, MarkType::kDefinedBy, R_N, E_N, M(Method) }
1211, { "Deprecated", nullptr, MarkType::kDeprecated, R_Y, E_N, 0 }
1212, { "Description", nullptr, MarkType::kDescription, R_Y, E_N, M(Example) }
1213, { "Doxygen", nullptr, MarkType::kDoxygen, R_Y, E_N, 0 }
1214, { "Enum", &fEnumMap, MarkType::kEnum, R_Y, E_O, M_CSST | M(Root) }
1215, { "EnumClass", &fClassMap, MarkType::kEnumClass, R_Y, E_O, M_CSST | M(Root) }
1216, { "Error", nullptr, MarkType::kError, R_N, E_N, M(Example) }
1217, { "Example", nullptr, MarkType::kExample, R_O, E_N, M_CSST | M_E | M(Method) }
Cary Clarkbad5ad72017-08-03 17:14:08 -04001218, { "Experimental", nullptr, MarkType::kExperimental, R_Y, E_N, 0 }
Cary Clarkce101242017-09-01 15:51:02 -04001219, { "External", nullptr, MarkType::kExternal, R_Y, E_N, M(Root) }
1220, { "File", nullptr, MarkType::kFile, R_N, E_N, M(Track) }
Ben Wagner63fd7602017-10-09 15:45:33 -04001221, { "Formula", nullptr, MarkType::kFormula, R_O, E_N,
Cary Clarkce101242017-09-01 15:51:02 -04001222 M(Column) | M_ST | M(Member) | M(Method) | M_D }
1223, { "Function", nullptr, MarkType::kFunction, R_O, E_N, M(Example) }
1224, { "Height", nullptr, MarkType::kHeight, R_N, E_N, M(Example) }
1225, { "Image", nullptr, MarkType::kImage, R_N, E_N, M(Example) }
1226, { "Legend", nullptr, MarkType::kLegend, R_Y, E_N, M(Table) }
1227, { "", nullptr, MarkType::kLink, R_N, E_N, M(Anchor) }
1228, { "List", nullptr, MarkType::kList, R_Y, E_N, M(Method) | M_CSST | M_E | M_D }
Cary Clark154beea2017-10-26 07:58:48 -04001229, { "Literal", nullptr, MarkType::kLiteral, R_N, E_N, M(Code) }
Cary Clarkce101242017-09-01 15:51:02 -04001230, { "", nullptr, MarkType::kMarkChar, R_N, E_N, 0 }
1231, { "Member", nullptr, MarkType::kMember, R_Y, E_N, M(Class) | M(Struct) }
1232, { "Method", &fMethodMap, MarkType::kMethod, R_Y, E_Y, M_CSST }
1233, { "NoExample", nullptr, MarkType::kNoExample, R_Y, E_N, 0 }
Cary Clark154beea2017-10-26 07:58:48 -04001234, { "Outdent", nullptr, MarkType::kOutdent, R_N, E_N, M(Code) }
Cary Clarkce101242017-09-01 15:51:02 -04001235, { "Param", nullptr, MarkType::kParam, R_Y, E_N, M(Method) }
1236, { "Platform", nullptr, MarkType::kPlatform, R_N, E_N, M(Example) }
1237, { "Private", nullptr, MarkType::kPrivate, R_N, E_N, 0 }
1238, { "Return", nullptr, MarkType::kReturn, R_Y, E_N, M(Method) }
1239, { "", nullptr, MarkType::kRoot, R_Y, E_N, 0 }
1240, { "", nullptr, MarkType::kRow, R_Y, E_N, M(Table) | M(List) }
Cary Clark3cd22cc2017-12-01 11:49:58 -05001241, { "SeeAlso", nullptr, MarkType::kSeeAlso, R_Y, E_N,
1242 M_CSST | M_E | M(Method) | M(Typedef) }
Cary Clark61dfc3a2018-01-03 08:37:53 -05001243, { "Set", nullptr, MarkType::kSet, R_N, E_N, M(Example) }
Cary Clarkce101242017-09-01 15:51:02 -04001244, { "StdOut", nullptr, MarkType::kStdOut, R_N, E_N, M(Example) }
1245, { "Struct", &fClassMap, MarkType::kStruct, R_Y, E_O, M(Class) | M(Root) | M_ST }
1246, { "Substitute", nullptr, MarkType::kSubstitute, R_N, E_N, M_ST }
1247, { "Subtopic", nullptr, MarkType::kSubtopic, R_Y, E_Y, M_CSST }
1248, { "Table", nullptr, MarkType::kTable, R_Y, E_N, M(Method) | M_CSST | M_E }
1249, { "Template", nullptr, MarkType::kTemplate, R_Y, E_N, 0 }
1250, { "", nullptr, MarkType::kText, R_Y, E_N, 0 }
1251, { "Time", nullptr, MarkType::kTime, R_Y, E_N, M(Track) }
1252, { "ToDo", nullptr, MarkType::kToDo, R_N, E_N, 0 }
1253, { "Topic", nullptr, MarkType::kTopic, R_Y, E_Y, M_CS | M(Root) | M(Topic) }
1254, { "Track", nullptr, MarkType::kTrack, R_Y, E_N, M_E | M_ST }
Cary Clarka560c472017-11-27 10:44:06 -05001255, { "Typedef", &fTypedefMap, MarkType::kTypedef, R_Y, E_N, M(Class) | M_ST }
Cary Clarkce101242017-09-01 15:51:02 -04001256, { "", nullptr, MarkType::kUnion, R_Y, E_N, 0 }
1257, { "Volatile", nullptr, MarkType::kVolatile, R_N, E_N, M(StdOut) }
1258, { "Width", nullptr, MarkType::kWidth, R_N, E_N, M(Example) } }
Cary Clarka560c472017-11-27 10:44:06 -05001259, fSkip(skip)
Cary Clark8032b982017-07-28 11:04:54 -04001260 {
1261 this->reset();
1262 }
1263
1264#undef R_O
1265#undef R_N
1266#undef R_Y
1267
1268#undef M_E
1269#undef M_CSST
1270#undef M_ST
1271#undef M_CS
1272#undef M_D
1273#undef M
1274
1275 ~BmhParser() override {}
1276
1277 bool addDefinition(const char* defStart, bool hasEnd, MarkType markType,
1278 const vector<string>& typeNameBuilder);
Cary Clark73fa9722017-08-29 17:36:51 -04001279 bool checkExamples() const;
Cary Clarka523d2d2017-08-30 08:58:10 -04001280 bool checkParamReturn(const Definition* definition) const;
Cary Clark73fa9722017-08-29 17:36:51 -04001281 bool dumpExamples(const char* fiddleJsonFileName) const;
Cary Clark8032b982017-07-28 11:04:54 -04001282 bool childOf(MarkType markType) const;
1283 string className(MarkType markType);
1284 bool collectExternals();
1285 int endHashCount() const;
Cary Clarkce101242017-09-01 15:51:02 -04001286 bool endTableColumn(const char* end, const char* terminator);
Cary Clark8032b982017-07-28 11:04:54 -04001287
1288 RootDefinition* findBmhObject(MarkType markType, const string& typeName) {
1289 auto map = fMaps[(int) markType].fBmh;
1290 if (!map) {
1291 return nullptr;
1292 }
1293 return &(*map)[typeName];
1294 }
1295
1296 bool findDefinitions();
1297 MarkType getMarkType(MarkLookup lookup) const;
1298 bool hasEndToken() const;
1299 string memberName();
1300 string methodName();
1301 const Definition* parentSpace() const;
1302
1303 bool parseFromFile(const char* path) override {
1304 if (!INHERITED::parseSetup(path)) {
1305 return false;
1306 }
1307 fCheckMethods = !strstr(path, "undocumented.bmh");
1308 return findDefinitions();
1309 }
1310
1311 bool popParentStack(Definition* definition);
Cary Clark73fa9722017-08-29 17:36:51 -04001312 void reportDuplicates(const Definition& def, const string& dup) const;
Cary Clark8032b982017-07-28 11:04:54 -04001313
1314 void reset() override {
1315 INHERITED::resetCommon();
1316 fRoot = nullptr;
Cary Clarkce101242017-09-01 15:51:02 -04001317 fWorkingColumn = nullptr;
1318 fRow = nullptr;
1319 fTableState = TableState::kNone;
Cary Clark8032b982017-07-28 11:04:54 -04001320 fMC = '#';
1321 fInChar = false;
1322 fInCharCommentString = false;
1323 fInComment = false;
1324 fInEnum = false;
1325 fInString = false;
1326 fCheckMethods = false;
1327 }
1328
1329 bool skipNoName();
1330 bool skipToDefinitionEnd(MarkType markType);
Cary Clarkce101242017-09-01 15:51:02 -04001331 void spellCheck(const char* match, SkCommandLineFlags::StringArray report) const;
Cary Clark2f466242017-12-11 16:03:17 -05001332 void spellStatus(const char* match, SkCommandLineFlags::StringArray report) const;
Cary Clark8032b982017-07-28 11:04:54 -04001333 vector<string> topicName();
1334 vector<string> typeName(MarkType markType, bool* expectEnd);
Cary Clark2f466242017-12-11 16:03:17 -05001335 string typedefName() override;
Cary Clark8032b982017-07-28 11:04:54 -04001336 string uniqueName(const string& base, MarkType markType);
1337 string uniqueRootName(const string& base, MarkType markType);
1338 void validate() const;
1339 string word(const string& prefix, const string& delimiter);
1340
1341public:
1342 struct DefinitionMap {
1343 const char* fName;
1344 unordered_map<string, RootDefinition>* fBmh;
1345 MarkType fMarkType;
1346 Resolvable fResolve;
1347 Exemplary fExemplary; // worthy of an example
1348 uint64_t fParentMask;
1349 };
Ben Wagner63fd7602017-10-09 15:45:33 -04001350
Cary Clark8032b982017-07-28 11:04:54 -04001351 DefinitionMap fMaps[Last_MarkType + 1];
1352 forward_list<RootDefinition> fTopics;
1353 forward_list<Definition> fMarkup;
1354 forward_list<RootDefinition> fExternals;
1355 vector<string> fInputFiles;
1356 unordered_map<string, RootDefinition> fClassMap;
1357 unordered_map<string, RootDefinition> fConstMap;
1358 unordered_map<string, RootDefinition> fEnumMap;
1359 unordered_map<string, RootDefinition> fMethodMap;
1360 unordered_map<string, RootDefinition> fTypedefMap;
1361 unordered_map<string, Definition*> fTopicMap;
1362 unordered_map<string, Definition*> fAliasMap;
1363 RootDefinition* fRoot;
Cary Clarkce101242017-09-01 15:51:02 -04001364 Definition* fWorkingColumn;
1365 Definition* fRow;
1366 const char* fColStart;
1367 TableState fTableState;
Cary Clark8032b982017-07-28 11:04:54 -04001368 mutable char fMC; // markup character
1369 bool fAnonymous;
1370 bool fCloned;
1371 bool fInChar;
1372 bool fInCharCommentString;
1373 bool fInEnum;
1374 bool fInComment;
1375 bool fInString;
1376 bool fCheckMethods;
Cary Clarka560c472017-11-27 10:44:06 -05001377 bool fSkip = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001378 bool fWroteOut = false;
Cary Clark8032b982017-07-28 11:04:54 -04001379private:
1380 typedef ParserCommon INHERITED;
1381};
1382
1383class IncludeParser : public ParserCommon {
1384public:
1385 enum class IsStruct {
1386 kNo,
1387 kYes,
1388 };
1389
1390 IncludeParser() : ParserCommon()
1391 , fMaps {
1392 { nullptr, MarkType::kNone }
1393 , { nullptr, MarkType::kAnchor }
1394 , { nullptr, MarkType::kAlias }
1395 , { nullptr, MarkType::kBug }
1396 , { nullptr, MarkType::kClass }
1397 , { nullptr, MarkType::kCode }
1398 , { nullptr, MarkType::kColumn }
1399 , { nullptr, MarkType::kComment }
1400 , { nullptr, MarkType::kConst }
1401 , { &fIDefineMap, MarkType::kDefine }
1402 , { nullptr, MarkType::kDefinedBy }
1403 , { nullptr, MarkType::kDeprecated }
1404 , { nullptr, MarkType::kDescription }
1405 , { nullptr, MarkType::kDoxygen }
1406 , { &fIEnumMap, MarkType::kEnum }
1407 , { &fIEnumMap, MarkType::kEnumClass }
1408 , { nullptr, MarkType::kError }
1409 , { nullptr, MarkType::kExample }
1410 , { nullptr, MarkType::kExperimental }
1411 , { nullptr, MarkType::kExternal }
1412 , { nullptr, MarkType::kFile }
1413 , { nullptr, MarkType::kFormula }
1414 , { nullptr, MarkType::kFunction }
1415 , { nullptr, MarkType::kHeight }
1416 , { nullptr, MarkType::kImage }
1417 , { nullptr, MarkType::kLegend }
1418 , { nullptr, MarkType::kLink }
1419 , { nullptr, MarkType::kList }
Cary Clark154beea2017-10-26 07:58:48 -04001420 , { nullptr, MarkType::kLiteral }
Cary Clark8032b982017-07-28 11:04:54 -04001421 , { nullptr, MarkType::kMarkChar }
1422 , { nullptr, MarkType::kMember }
1423 , { nullptr, MarkType::kMethod }
1424 , { nullptr, MarkType::kNoExample }
Cary Clark154beea2017-10-26 07:58:48 -04001425 , { nullptr, MarkType::kOutdent }
Cary Clark8032b982017-07-28 11:04:54 -04001426 , { nullptr, MarkType::kParam }
1427 , { nullptr, MarkType::kPlatform }
1428 , { nullptr, MarkType::kPrivate }
1429 , { nullptr, MarkType::kReturn }
1430 , { nullptr, MarkType::kRoot }
1431 , { nullptr, MarkType::kRow }
1432 , { nullptr, MarkType::kSeeAlso }
Cary Clark61dfc3a2018-01-03 08:37:53 -05001433 , { nullptr, MarkType::kSet }
Cary Clark8032b982017-07-28 11:04:54 -04001434 , { nullptr, MarkType::kStdOut }
1435 , { &fIStructMap, MarkType::kStruct }
1436 , { nullptr, MarkType::kSubstitute }
1437 , { nullptr, MarkType::kSubtopic }
1438 , { nullptr, MarkType::kTable }
1439 , { &fITemplateMap, MarkType::kTemplate }
1440 , { nullptr, MarkType::kText }
1441 , { nullptr, MarkType::kTime }
1442 , { nullptr, MarkType::kToDo }
1443 , { nullptr, MarkType::kTopic }
1444 , { nullptr, MarkType::kTrack }
1445 , { &fITypedefMap, MarkType::kTypedef }
1446 , { &fIUnionMap, MarkType::kUnion }
1447 , { nullptr, MarkType::kVolatile }
1448 , { nullptr, MarkType::kWidth } }
1449 {
1450 this->reset();
1451 }
1452
1453 ~IncludeParser() override {}
1454
1455 void addKeyword(KeyWord keyWord);
1456
1457 void addPunctuation(Punctuation punctuation) {
1458 fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent);
1459 }
1460
1461 void addWord() {
1462 fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent);
1463 fIncludeWord = nullptr;
1464 }
1465
1466 void checkForMissingParams(const vector<string>& methodParams,
1467 const vector<string>& foundParams);
1468 bool checkForWord();
1469 string className() const;
1470 bool crossCheck(BmhParser& );
1471 IClassDefinition* defineClass(const Definition& includeDef, const string& className);
1472 void dumpClassTokens(IClassDefinition& classDef);
Cary Clark9174bda2017-09-19 17:39:32 -04001473 void dumpComment(const Definition& );
1474 void dumpEnum(const Definition& );
1475 void dumpMethod(const Definition& );
1476 void dumpMember(const Definition& );
Cary Clarkd0530ba2017-09-14 11:25:39 -04001477 bool dumpTokens(const string& directory);
Cary Clark9174bda2017-09-19 17:39:32 -04001478 bool dumpTokens(const string& directory, const string& skClassName);
Cary Clark8032b982017-07-28 11:04:54 -04001479 bool findComments(const Definition& includeDef, Definition* markupDef);
1480
1481 Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
1482 const string& typeName) {
1483 typedef Definition* DefinitionPtr;
1484 unordered_map<string, Definition>* map = fMaps[(int) markType].fInclude;
1485 if (!map) {
1486 return reportError<DefinitionPtr>("invalid mark type");
1487 }
1488 string name = this->uniqueName(*map, typeName);
1489 Definition& markupDef = (*map)[name];
1490 if (markupDef.fStart) {
1491 return reportError<DefinitionPtr>("definition already defined");
1492 }
1493 markupDef.fFileName = fFileName;
1494 markupDef.fStart = includeDef.fStart;
1495 markupDef.fContentStart = includeDef.fStart;
1496 markupDef.fName = name;
1497 markupDef.fContentEnd = includeDef.fContentEnd;
1498 markupDef.fTerminator = includeDef.fTerminator;
1499 markupDef.fParent = fParent;
1500 markupDef.fLineCount = includeDef.fLineCount;
1501 markupDef.fMarkType = markType;
1502 markupDef.fKeyWord = includeDef.fKeyWord;
1503 markupDef.fType = Definition::Type::kMark;
1504 return &markupDef;
1505 }
1506
1507 static KeyWord FindKey(const char* start, const char* end);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001508 bool internalName(const Definition& ) const;
Cary Clark8032b982017-07-28 11:04:54 -04001509 bool parseChar();
1510 bool parseComment(const string& filename, const char* start, const char* end, int lineCount,
1511 Definition* markupDef);
1512 bool parseClass(Definition* def, IsStruct);
1513 bool parseDefine();
1514 bool parseEnum(Definition* child, Definition* markupDef);
1515
1516 bool parseFromFile(const char* path) override {
Cary Clark2f466242017-12-11 16:03:17 -05001517 this->reset();
Cary Clark8032b982017-07-28 11:04:54 -04001518 if (!INHERITED::parseSetup(path)) {
1519 return false;
1520 }
1521 string name(path);
1522 return parseInclude(name);
1523 }
1524
1525 bool parseInclude(const string& name);
1526 bool parseMember(Definition* child, Definition* markupDef);
1527 bool parseMethod(Definition* child, Definition* markupDef);
1528 bool parseObject(Definition* child, Definition* markupDef);
1529 bool parseObjects(Definition* parent, Definition* markupDef);
1530 bool parseTemplate();
Cary Clark2f466242017-12-11 16:03:17 -05001531 bool parseTypedef(Definition* child, Definition* markupDef);
Cary Clark8032b982017-07-28 11:04:54 -04001532 bool parseUnion();
1533
1534 void popBracket() {
1535 SkASSERT(Definition::Type::kBracket == fParent->fType);
1536 this->popObject();
1537 Bracket bracket = this->topBracket();
1538 this->setBracketShortCuts(bracket);
1539 }
1540
1541 void pushBracket(Bracket bracket) {
1542 this->setBracketShortCuts(bracket);
1543 fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent);
1544 Definition* container = &fParent->fTokens.back();
1545 this->addDefinition(container);
1546 }
1547
1548 void reset() override {
1549 INHERITED::resetCommon();
1550 fRootTopic = nullptr;
1551 fInBrace = nullptr;
1552 fIncludeWord = nullptr;
Cary Clark73fa9722017-08-29 17:36:51 -04001553 fLastObject = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001554 fPrev = '\0';
1555 fInChar = false;
1556 fInCharCommentString = false;
1557 fInComment = false;
1558 fInEnum = false;
1559 fInFunction = false;
1560 fInString = false;
Cary Clarkf059e7c2017-12-20 14:53:21 -05001561 fFailed = false;
Cary Clark7cfcbca2018-01-04 16:11:51 -05001562 fPriorEnum = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001563 }
1564
1565 void setBracketShortCuts(Bracket bracket) {
1566 fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket;
1567 fInString = Bracket::kString == bracket;
1568 fInChar = Bracket::kChar == bracket;
1569 fInCharCommentString = fInChar || fInComment || fInString;
1570 }
1571
1572 Bracket topBracket() const {
1573 Definition* parent = fParent;
1574 while (parent && Definition::Type::kBracket != parent->fType) {
1575 parent = parent->fParent;
1576 }
1577 return parent ? parent->fBracket : Bracket::kNone;
1578 }
1579
1580 template <typename T>
1581 string uniqueName(const unordered_map<string, T>& m, const string& typeName) {
1582 string base(typeName.size() > 0 ? typeName : "_anonymous");
1583 string name(base);
1584 int anonCount = 1;
1585 do {
1586 auto iter = m.find(name);
1587 if (iter == m.end()) {
1588 return name;
1589 }
1590 name = base + '_';
1591 name += to_string(++anonCount);
1592 } while (true);
1593 // should never get here
1594 return string();
1595 }
1596
1597 void validate() const;
1598
Cary Clark9174bda2017-09-19 17:39:32 -04001599 void writeDefinition(const Definition& def) {
1600 if (def.length() > 1) {
1601 this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1602 this->lf(1);
1603 }
1604 }
1605
1606 void writeDefinition(const Definition& def, const string& name, int spaces) {
1607 this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
1608 this->writeSpace(spaces);
1609 this->writeString(name);
1610 this->lf(1);
1611 }
1612
1613 void writeEndTag() {
1614 this->lf(1);
1615 this->writeString("##");
1616 this->lf(1);
1617 }
1618
1619 void writeEndTag(const char* tagType) {
1620 this->lf(1);
1621 this->writeString(string("#") + tagType + " ##");
1622 this->lf(1);
1623 }
1624
1625 void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) {
1626 this->lf(1);
1627 this->writeString(string("#") + tagType + " " + tagID);
1628 this->writeSpace(spaces);
1629 this->writeString("##");
1630 this->lf(1);
1631 }
1632
1633 void writeEndTag(const char* tagType, const string& tagID, int spaces = 1) {
1634 this->writeEndTag(tagType, tagID.c_str(), spaces);
1635 }
1636
Cary Clark154beea2017-10-26 07:58:48 -04001637 void writeIncompleteTag(const char* tagType, const string& tagID, int spaces = 1) {
1638 this->writeString(string("#") + tagType + " " + tagID);
1639 this->writeSpace(spaces);
1640 this->writeString("incomplete");
1641 this->writeSpace();
1642 this->writeString("##");
1643 this->lf(1);
1644 }
1645
1646 void writeIncompleteTag(const char* tagType) {
1647 this->writeString(string("#") + tagType + " incomplete ##");
1648 this->lf(1);
1649 }
1650
Cary Clark9174bda2017-09-19 17:39:32 -04001651 void writeTableHeader(const char* col1, size_t pad, const char* col2) {
1652 this->lf(1);
1653 this->writeString("#Table");
1654 this->lf(1);
1655 this->writeString("#Legend");
1656 this->lf(1);
1657 string legend = "# ";
1658 legend += col1;
1659 if (pad > strlen(col1)) {
1660 legend += string(pad - strlen(col1), ' ');
1661 }
1662 legend += " # ";
1663 legend += col2;
1664 legend += " ##";
1665 this->writeString(legend);
1666 this->lf(1);
1667 this->writeString("#Legend ##");
1668 this->lf(1);
1669 }
1670
1671 void writeTableRow(size_t pad, const string& col1) {
1672 this->lf(1);
1673 string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##";
1674 this->writeString(row);
1675 this->lf(1);
1676 }
1677
1678 void writeTableTrailer() {
1679 this->lf(1);
1680 this->writeString("#Table ##");
1681 this->lf(1);
1682 }
1683
1684 void writeTag(const char* tagType) {
1685 this->lf(1);
1686 this->writeString("#");
1687 this->writeString(tagType);
1688 }
1689
1690 void writeTagNoLF(const char* tagType, const char* tagID) {
1691 this->writeString("#");
1692 this->writeString(tagType);
1693 this->writeSpace();
1694 this->writeString(tagID);
1695 }
1696
1697 void writeTagNoLF(const char* tagType, const string& tagID) {
1698 this->writeTagNoLF(tagType, tagID.c_str());
1699 }
1700
1701 void writeTag(const char* tagType, const char* tagID) {
1702 this->lf(1);
1703 this->writeTagNoLF(tagType, tagID);
1704 }
1705
1706 void writeTag(const char* tagType, const string& tagID) {
1707 this->writeTag(tagType, tagID.c_str());
1708 }
1709
Cary Clark8032b982017-07-28 11:04:54 -04001710protected:
1711 static void ValidateKeyWords();
1712
1713 struct DefinitionMap {
1714 unordered_map<string, Definition>* fInclude;
1715 MarkType fMarkType;
1716 };
Ben Wagner63fd7602017-10-09 15:45:33 -04001717
Cary Clark8032b982017-07-28 11:04:54 -04001718 DefinitionMap fMaps[Last_MarkType + 1];
1719 unordered_map<string, Definition> fIncludeMap;
1720 unordered_map<string, IClassDefinition> fIClassMap;
1721 unordered_map<string, Definition> fIDefineMap;
1722 unordered_map<string, Definition> fIEnumMap;
Cary Clarka560c472017-11-27 10:44:06 -05001723 unordered_map<string, Definition> fIFunctionMap;
Cary Clark8032b982017-07-28 11:04:54 -04001724 unordered_map<string, Definition> fIStructMap;
1725 unordered_map<string, Definition> fITemplateMap;
1726 unordered_map<string, Definition> fITypedefMap;
1727 unordered_map<string, Definition> fIUnionMap;
1728 Definition* fRootTopic;
1729 Definition* fInBrace;
Cary Clark73fa9722017-08-29 17:36:51 -04001730 Definition* fLastObject;
Cary Clark7cfcbca2018-01-04 16:11:51 -05001731 Definition* fPriorEnum;
1732 int fPriorIndex;
Cary Clark8032b982017-07-28 11:04:54 -04001733 const char* fIncludeWord;
1734 char fPrev;
1735 bool fInChar;
1736 bool fInCharCommentString;
1737 bool fInComment;
1738 bool fInEnum;
1739 bool fInFunction;
1740 bool fInString;
Cary Clarkf059e7c2017-12-20 14:53:21 -05001741 bool fFailed;
Cary Clark8032b982017-07-28 11:04:54 -04001742
1743 typedef ParserCommon INHERITED;
1744};
1745
1746class IncludeWriter : public IncludeParser {
1747public:
1748 enum class Word {
1749 kStart,
1750 kCap,
1751 kFirst,
1752 kUnderline,
1753 kMixed,
1754 };
1755
Cary Clarkd0530ba2017-09-14 11:25:39 -04001756 enum class Phrase {
1757 kNo,
1758 kYes,
1759 };
1760
Cary Clark8032b982017-07-28 11:04:54 -04001761 enum class PunctuationState {
1762 kStart,
1763 kDelimiter,
1764 kPeriod,
Cary Clark1eace2d2017-07-31 07:52:43 -04001765 kSpace,
Cary Clark8032b982017-07-28 11:04:54 -04001766 };
1767
Cary Clarkce101242017-09-01 15:51:02 -04001768 enum class RefType {
1769 kUndefined,
1770 kNormal,
1771 kExternal,
1772 };
1773
Cary Clark8032b982017-07-28 11:04:54 -04001774 enum class Wrote {
1775 kNone,
1776 kLF,
1777 kChars,
1778 };
1779
Cary Clarkbad5ad72017-08-03 17:14:08 -04001780 struct IterState {
Ben Wagner63fd7602017-10-09 15:45:33 -04001781 IterState (list<Definition>::iterator tIter, list<Definition>::iterator tIterEnd)
Cary Clarkbad5ad72017-08-03 17:14:08 -04001782 : fDefIter(tIter)
1783 , fDefEnd(tIterEnd) {
1784 }
1785 list<Definition>::iterator fDefIter;
1786 list<Definition>::iterator fDefEnd;
1787 };
1788
Cary Clark73fa9722017-08-29 17:36:51 -04001789 struct ParentPair {
1790 const Definition* fParent;
1791 const ParentPair* fPrev;
1792 };
1793
Cary Clarkbef063a2017-10-31 15:44:45 -04001794 IncludeWriter() : IncludeParser() {
1795 this->reset();
1796 }
1797
Cary Clark8032b982017-07-28 11:04:54 -04001798 ~IncludeWriter() override {}
1799
1800 bool contentFree(int size, const char* data) const {
1801 while (size > 0 && data[0] <= ' ') {
1802 --size;
1803 ++data;
1804 }
1805 while (size > 0 && data[size - 1] <= ' ') {
1806 --size;
1807 }
1808 return 0 == size;
1809 }
1810
Cary Clark6fc50412017-09-21 12:31:06 -04001811 void descriptionOut(const Definition* def);
Cary Clark8032b982017-07-28 11:04:54 -04001812 void enumHeaderOut(const RootDefinition* root, const Definition& child);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001813 void enumMembersOut(const RootDefinition* root, Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001814 void enumSizeItems(const Definition& child);
1815 int lookupMethod(const PunctuationState punctuation, const Word word,
Ben Wagner63fd7602017-10-09 15:45:33 -04001816 const int start, const int run, int lastWrite,
Cary Clark6fc50412017-09-21 12:31:06 -04001817 const char* data, bool hasIndirection);
Cary Clark8032b982017-07-28 11:04:54 -04001818 int lookupReference(const PunctuationState punctuation, const Word word,
Ben Wagner63fd7602017-10-09 15:45:33 -04001819 const int start, const int run, int lastWrite, const char last,
Cary Clark8032b982017-07-28 11:04:54 -04001820 const char* data);
Cary Clark579985c2017-07-31 11:48:27 -04001821 void methodOut(const Definition* method, const Definition& child);
Cary Clark73fa9722017-08-29 17:36:51 -04001822 bool populate(Definition* def, ParentPair* parentPair, RootDefinition* root);
Cary Clark8032b982017-07-28 11:04:54 -04001823 bool populate(BmhParser& bmhParser);
1824
1825 void reset() override {
1826 INHERITED::resetCommon();
Cary Clark579985c2017-07-31 11:48:27 -04001827 fBmhMethod = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001828 fBmhParser = nullptr;
1829 fEnumDef = nullptr;
Cary Clark579985c2017-07-31 11:48:27 -04001830 fMethodDef = nullptr;
Cary Clark154beea2017-10-26 07:58:48 -04001831 fBmhStructDef = nullptr;
Cary Clark73fa9722017-08-29 17:36:51 -04001832 fAttrDeprecated = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04001833 fInStruct = false;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001834 fWroteMethod = false;
Cary Clark154beea2017-10-26 07:58:48 -04001835 fIndentNext = false;
1836 fPendingMethod = false;
Cary Clark8032b982017-07-28 11:04:54 -04001837 }
1838
1839 string resolveMethod(const char* start, const char* end, bool first);
Cary Clarkce101242017-09-01 15:51:02 -04001840 string resolveRef(const char* start, const char* end, bool first, RefType* refType);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001841 Wrote rewriteBlock(int size, const char* data, Phrase phrase);
Cary Clarkbad5ad72017-08-03 17:14:08 -04001842 Definition* structMemberOut(const Definition* memberStart, const Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001843 void structOut(const Definition* root, const Definition& child,
1844 const char* commentStart, const char* commentEnd);
Cary Clark884dd7d2017-10-11 10:37:52 -04001845 void structSizeMembers(const Definition& child);
Cary Clark8032b982017-07-28 11:04:54 -04001846private:
1847 BmhParser* fBmhParser;
1848 Definition* fDeferComment;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001849 Definition* fLastComment;
Cary Clark579985c2017-07-31 11:48:27 -04001850 const Definition* fBmhMethod;
Cary Clark8032b982017-07-28 11:04:54 -04001851 const Definition* fEnumDef;
Cary Clark579985c2017-07-31 11:48:27 -04001852 const Definition* fMethodDef;
Cary Clark154beea2017-10-26 07:58:48 -04001853 const Definition* fBmhStructDef;
Cary Clark73fa9722017-08-29 17:36:51 -04001854 const Definition* fAttrDeprecated;
Cary Clark8032b982017-07-28 11:04:54 -04001855 const char* fContinuation; // used to construct paren-qualified method name
1856 int fAnonymousEnumCount;
1857 int fEnumItemValueTab;
1858 int fEnumItemCommentTab;
1859 int fStructMemberTab;
Cary Clarkbad5ad72017-08-03 17:14:08 -04001860 int fStructValueTab;
Cary Clark8032b982017-07-28 11:04:54 -04001861 int fStructCommentTab;
1862 bool fInStruct;
Cary Clarkd0530ba2017-09-14 11:25:39 -04001863 bool fWroteMethod;
Cary Clark154beea2017-10-26 07:58:48 -04001864 bool fIndentNext;
1865 bool fPendingMethod;
Cary Clark8032b982017-07-28 11:04:54 -04001866
1867 typedef IncludeParser INHERITED;
1868};
1869
Cary Clarkbef063a2017-10-31 15:44:45 -04001870class FiddleBase : public ParserCommon {
1871protected:
1872 FiddleBase(BmhParser* bmh) : ParserCommon()
1873 , fBmhParser(bmh)
1874 , fContinuation(false)
1875 , fTextOut(false)
1876 , fPngOut(false)
1877 {
Cary Clark8032b982017-07-28 11:04:54 -04001878 this->reset();
1879 }
1880
Cary Clarkbef063a2017-10-31 15:44:45 -04001881 void reset() override {
1882 INHERITED::resetCommon();
1883 }
1884
Cary Clark8032b982017-07-28 11:04:54 -04001885 Definition* findExample(const string& name) const;
Cary Clarkbef063a2017-10-31 15:44:45 -04001886 bool parseFiddles();
1887 virtual bool pngOut(Definition* example) = 0;
1888 virtual bool textOut(Definition* example, const char* stdOutStart,
1889 const char* stdOutEnd) = 0;
1890
1891 BmhParser* fBmhParser; // must be writable; writes example hash
1892 string fFullName;
1893 bool fContinuation;
1894 bool fTextOut;
1895 bool fPngOut;
1896private:
1897 typedef ParserCommon INHERITED;
1898};
1899
1900class FiddleParser : public FiddleBase {
1901public:
1902 FiddleParser(BmhParser* bmh) : FiddleBase(bmh) {
1903 fTextOut = true;
1904 }
Cary Clark8032b982017-07-28 11:04:54 -04001905
1906 bool parseFromFile(const char* path) override {
1907 if (!INHERITED::parseSetup(path)) {
1908 return false;
1909 }
1910 return parseFiddles();
1911 }
1912
Cary Clarkbef063a2017-10-31 15:44:45 -04001913private:
1914 bool pngOut(Definition* example) override {
1915 return true;
Cary Clark8032b982017-07-28 11:04:54 -04001916 }
1917
Cary Clarkbef063a2017-10-31 15:44:45 -04001918 bool textOut(Definition* example, const char* stdOutStart,
1919 const char* stdOutEnd) override;
1920
1921 typedef FiddleBase INHERITED;
1922};
1923
1924class Catalog : public FiddleBase {
1925public:
1926 Catalog(BmhParser* bmh) : FiddleBase(bmh) {}
1927
1928 bool appendFile(const string& path);
1929 bool closeCatalog();
1930 bool openCatalog(const char* inDir, const char* outDir);
Cary Clark2f466242017-12-11 16:03:17 -05001931 bool openStatus(const char* inDir, const char* outDir);
Cary Clarkbef063a2017-10-31 15:44:45 -04001932
1933 bool parseFromFile(const char* path) override ;
Cary Clark8032b982017-07-28 11:04:54 -04001934private:
Cary Clarkbef063a2017-10-31 15:44:45 -04001935 bool pngOut(Definition* example) override;
1936 bool textOut(Definition* example, const char* stdOutStart,
1937 const char* stdOutEnd) override;
Cary Clark8032b982017-07-28 11:04:54 -04001938
Cary Clarkbef063a2017-10-31 15:44:45 -04001939 string fDocsDir;
Cary Clark8032b982017-07-28 11:04:54 -04001940
Cary Clarkbef063a2017-10-31 15:44:45 -04001941 typedef FiddleBase INHERITED;
Cary Clark8032b982017-07-28 11:04:54 -04001942};
1943
1944class HackParser : public ParserCommon {
1945public:
1946 HackParser() : ParserCommon() {
1947 this->reset();
1948 }
1949
1950 bool parseFromFile(const char* path) override {
1951 if (!INHERITED::parseSetup(path)) {
1952 return false;
1953 }
1954 return hackFiles();
1955 }
1956
1957 void reset() override {
1958 INHERITED::resetCommon();
1959 }
1960
1961private:
1962 bool hackFiles();
1963
1964 typedef ParserCommon INHERITED;
1965};
1966
1967class MdOut : public ParserCommon {
1968public:
1969 MdOut(const BmhParser& bmh) : ParserCommon()
1970 , fBmhParser(bmh) {
1971 this->reset();
1972 }
1973
Cary Clark7cfcbca2018-01-04 16:11:51 -05001974 bool buildReferences(const char* docDir, const char* mdOutDirOrFile);
1975 bool buildStatus(const char* docDir, const char* mdOutDir);
Cary Clark8032b982017-07-28 11:04:54 -04001976private:
1977 enum class TableState {
1978 kNone,
1979 kRow,
1980 kColumn,
1981 };
1982
1983 string addReferences(const char* start, const char* end, BmhParser::Resolvable );
1984 bool buildRefFromFile(const char* fileName, const char* outDir);
Cary Clarka523d2d2017-08-30 08:58:10 -04001985 bool checkParamReturnBody(const Definition* def) const;
Cary Clark8032b982017-07-28 11:04:54 -04001986 void childrenOut(const Definition* def, const char* contentStart);
Cary Clarkd0530ba2017-09-14 11:25:39 -04001987 const Definition* findParamType();
Cary Clark8032b982017-07-28 11:04:54 -04001988 const Definition* isDefined(const TextParser& parser, const string& ref, bool report) const;
1989 string linkName(const Definition* ) const;
1990 string linkRef(const string& leadingSpaces, const Definition*, const string& ref) const;
1991 void markTypeOut(Definition* );
Ben Wagner63fd7602017-10-09 15:45:33 -04001992 void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); }
Cary Clark8032b982017-07-28 11:04:54 -04001993 void mdHeaderOutLF(int depth, int lf);
1994 bool parseFromFile(const char* path) override {
1995 return true;
1996 }
1997
1998 void reset() override {
1999 INHERITED::resetCommon();
Cary Clarkbad5ad72017-08-03 17:14:08 -04002000 fEnumClass = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04002001 fMethod = nullptr;
2002 fRoot = nullptr;
Cary Clarkd0530ba2017-09-14 11:25:39 -04002003 fLastParam = nullptr;
Cary Clark8032b982017-07-28 11:04:54 -04002004 fTableState = TableState::kNone;
2005 fHasFiddle = false;
2006 fInDescription = false;
2007 fInList = false;
Cary Clarka560c472017-11-27 10:44:06 -05002008 fRespectLeadingSpace = false;
Cary Clark8032b982017-07-28 11:04:54 -04002009 }
2010
Cary Clark154beea2017-10-26 07:58:48 -04002011 BmhParser::Resolvable resolvable(const Definition* definition) const {
2012 MarkType markType = definition->fMarkType;
2013 if (MarkType::kCode == markType) {
2014 for (auto child : definition->fChildren) {
2015 if (MarkType::kLiteral == child->fMarkType) {
2016 return BmhParser::Resolvable::kLiteral;
2017 }
2018 }
2019 }
Ben Wagner63fd7602017-10-09 15:45:33 -04002020 if ((MarkType::kExample == markType
Cary Clark8032b982017-07-28 11:04:54 -04002021 || MarkType::kFunction == markType) && fHasFiddle) {
2022 return BmhParser::Resolvable::kNo;
2023 }
2024 return fBmhParser.fMaps[(int) markType].fResolve;
2025 }
2026
2027 void resolveOut(const char* start, const char* end, BmhParser::Resolvable );
2028
2029 const BmhParser& fBmhParser;
Cary Clarkbad5ad72017-08-03 17:14:08 -04002030 const Definition* fEnumClass;
Cary Clark8032b982017-07-28 11:04:54 -04002031 Definition* fMethod;
2032 RootDefinition* fRoot;
Cary Clarkd0530ba2017-09-14 11:25:39 -04002033 const Definition* fLastParam;
Cary Clark8032b982017-07-28 11:04:54 -04002034 TableState fTableState;
2035 bool fHasFiddle;
2036 bool fInDescription; // FIXME: for now, ignore unfound camelCase in description since it may
2037 // be defined in example which at present cannot be linked to
2038 bool fInList;
Cary Clarka560c472017-11-27 10:44:06 -05002039 bool fRespectLeadingSpace;
Cary Clark8032b982017-07-28 11:04:54 -04002040 typedef ParserCommon INHERITED;
2041};
2042
2043
2044// some methods cannot be trivially parsed; look for class-name / ~ / operator
2045class MethodParser : public TextParser {
2046public:
2047 MethodParser(const string& className, const string& fileName,
2048 const char* start, const char* end, int lineCount)
2049 : TextParser(fileName, start, end, lineCount)
2050 , fClassName(className) {
2051 }
2052
Cary Clark2f466242017-12-11 16:03:17 -05002053 ~MethodParser() override {}
2054
Cary Clark8032b982017-07-28 11:04:54 -04002055 void skipToMethodStart() {
2056 if (!fClassName.length()) {
2057 this->skipToAlphaNum();
2058 return;
2059 }
2060 while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
2061 this->next();
2062 }
2063 }
2064
2065 void skipToMethodEnd() {
2066 if (this->eof()) {
2067 return;
2068 }
2069 if (fClassName.length()) {
2070 if ('~' == this->peek()) {
2071 this->next();
2072 if (!this->startsWith(fClassName.c_str())) {
2073 --fChar;
2074 return;
2075 }
2076 }
2077 if (this->startsWith(fClassName.c_str()) || this->startsWith("operator")) {
Cary Clarka560c472017-11-27 10:44:06 -05002078 const char* ptr = this->anyOf("\n (");
Cary Clark8032b982017-07-28 11:04:54 -04002079 if (ptr && '(' == *ptr) {
2080 this->skipToEndBracket(')');
2081 SkAssertResult(')' == this->next());
Cary Clarka560c472017-11-27 10:44:06 -05002082 this->skipExact("_const");
Cary Clark8032b982017-07-28 11:04:54 -04002083 return;
2084 }
2085 }
2086 }
2087 if (this->startsWith("Sk") && this->wordEndsWith(".h")) { // allow include refs
2088 this->skipToNonAlphaNum();
2089 } else {
2090 this->skipFullName();
Cary Clarka560c472017-11-27 10:44:06 -05002091 if (this->endsWith("operator")) {
2092 const char* ptr = this->anyOf("\n (");
2093 if (ptr && '(' == *ptr) {
2094 this->skipToEndBracket(')');
2095 SkAssertResult(')' == this->next());
2096 this->skipExact("_const");
2097 }
2098 }
Cary Clark8032b982017-07-28 11:04:54 -04002099 }
2100 }
2101
2102 bool wordEndsWith(const char* str) const {
2103 const char* space = this->strnchr(' ', fEnd);
2104 if (!space) {
2105 return false;
2106 }
2107 size_t len = strlen(str);
2108 if (space < fChar + len) {
2109 return false;
2110 }
2111 return !strncmp(str, space - len, len);
2112 }
2113
2114private:
2115 string fClassName;
2116 typedef TextParser INHERITED;
2117};
2118
2119#endif