| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2017 Google Inc. | 
 | 3 |  * | 
 | 4 |  * Use of this source code is governed by a BSD-style license that can be | 
 | 5 |  * found in the LICENSE file. | 
 | 6 |  */ | 
 | 7 |  | 
 | 8 | #include "bookmaker.h" | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 9 | #include <chrono> | 
 | 10 | #include <ctime> | 
 | 11 | #include <string> | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 12 |  | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 13 | bool IncludeWriter::checkChildCommentLength(const Definition* parent, MarkType childType) const { | 
 | 14 |     bool oneMember = false; | 
 | 15 |     for (auto& item : parent->fChildren) { | 
 | 16 |         if (childType != item->fMarkType) { | 
 | 17 |             continue; | 
 | 18 |         } | 
 | 19 |         oneMember = true; | 
 | 20 |         int lineLen = 0; | 
 | 21 |         for (auto& itemChild : item->fChildren) { | 
 | 22 |             if (MarkType::kExperimental == itemChild->fMarkType) { | 
 | 23 |                 lineLen = sizeof("experimental") - 1; | 
 | 24 |                 break; | 
 | 25 |             } | 
 | 26 |             if (MarkType::kDeprecated == itemChild->fMarkType) { | 
 | 27 |                 lineLen = sizeof("deprecated") - 1; | 
 | 28 |                 // todo: look for 'soon' | 
 | 29 |                 break; | 
 | 30 |             } | 
 | 31 |             if (MarkType::kLine == itemChild->fMarkType) { | 
 | 32 |                 lineLen = itemChild->length(); | 
 | 33 |                 break; | 
 | 34 |             } | 
 | 35 |         } | 
 | 36 |         if (!lineLen) { | 
 | 37 |             item->reportError<void>("missing #Line"); | 
 | 38 |         } | 
 | 39 |         if (fEnumItemCommentTab + lineLen >= 100) { | 
 | 40 | // if too long, remove spaces until it fits, or wrap | 
 | 41 | //            item->reportError<void>("#Line comment too long"); | 
 | 42 |         } | 
 | 43 |     } | 
 | 44 |     return oneMember; | 
 | 45 | } | 
 | 46 |  | 
 | 47 | void IncludeWriter::checkEnumLengths(const Definition& child, string enumName, ItemLength* length) const { | 
 | 48 |     const Definition* enumItem = this->matchMemberName(enumName, child); | 
 | 49 |     if (std::any_of(enumItem->fChildren.begin(), enumItem->fChildren.end(), | 
 | 50 |             [](Definition* child){return MarkType::kNoJustify == child->fMarkType;})) { | 
 | 51 |         return; | 
 | 52 |     } | 
 | 53 |     string comment = this->enumMemberComment(enumItem, child); | 
 | 54 |     int lineLimit = 100 - fIndent - 7; // 7: , space //!< space | 
 | 55 |     if (length->fCurValue) { | 
 | 56 |         lineLimit -= 3; // space = space | 
 | 57 |     } | 
 | 58 |     if (length->fCurName + length->fCurValue + (int) comment.length() < lineLimit) { | 
 | 59 |         length->fLongestName = SkTMax(length->fLongestName, length->fCurName); | 
 | 60 |         length->fLongestValue = SkTMax(length->fLongestValue, length->fCurValue); | 
 | 61 |     } | 
 | 62 | } | 
 | 63 |  | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 64 | void IncludeWriter::constOut(const Definition* memberStart, const Definition* bmhConst) { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 65 |     const char* bodyEnd = fDeferComment ? fDeferComment->fContentStart - 1 : | 
 | 66 |         memberStart->fContentStart; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 67 |     this->firstBlockTrim((int) (bodyEnd - fStart), fStart);  // may write nothing | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 68 |     this->lf(2); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 69 |     this->indentDeferred(IndentKind::kConstOut); | 
 | 70 |     if (fStructEnded) { | 
 | 71 |         fIndent = fICSStack.size() * 4; | 
 | 72 |         fStructEnded = false; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 73 |     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 74 |     // comment may be legitimately empty; typedef may not have separate comment (for now) | 
 | 75 |     fReturnOnWrite = true; | 
 | 76 |     bool commentHasLength = this->descriptionOut(bmhConst, SkipFirstLine::kYes, Phrase::kNo); | 
 | 77 |     fReturnOnWrite = false; | 
 | 78 |     if (commentHasLength) { | 
 | 79 |         this->writeCommentHeader(); | 
 | 80 |         fIndent += 4; | 
 | 81 |         if (!this->descriptionOut(bmhConst, SkipFirstLine::kYes, Phrase::kNo)) { | 
 | 82 |             return memberStart->reportError<void>("expected description for const"); | 
 | 83 |         } | 
 | 84 |         fIndent -= 4; | 
 | 85 |         this->writeCommentTrailer(OneLine::kNo); | 
 | 86 |     } | 
 | 87 |     this->setStart(memberStart->fContentStart, memberStart); | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 88 | } | 
 | 89 |  | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 90 | bool IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirstLine, | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 91 |             Phrase phrase) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 92 |     bool wroteSomething = false; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 93 |     const char* commentStart = def->fContentStart; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 94 |     if (SkipFirstLine::kYes == skipFirstLine) { | 
 | 95 |         TextParser parser(def); | 
 | 96 |         SkAssertResult(parser.skipLine()); | 
 | 97 |         commentStart = parser.fChar; | 
 | 98 |     } | 
 | 99 |     int commentLen = (int) (def->fContentEnd - commentStart); | 
 | 100 |     bool breakOut = false; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 101 |     SkDEBUGCODE(bool wroteCode = false); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 102 |     if (def->fDeprecated) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 103 |         if (fReturnOnWrite) { | 
 | 104 |             return true; | 
 | 105 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 106 |         string message = def->incompleteMessage(Definition::DetailsType::kSentence); | 
 | 107 |         this->writeString(message); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 108 |         this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 109 |         wroteSomething = true; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 110 |     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 111 |     const Definition* lastDescription = def; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 112 |     for (auto prop : def->fChildren) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 113 |         fLastDescription = lastDescription; | 
 | 114 |         lastDescription = prop; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 115 |         switch (prop->fMarkType) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 116 |             case MarkType::kCode: { | 
 | 117 |                 bool literal = false; | 
 | 118 |                 bool literalOutdent = false; | 
 | 119 |                 commentLen = (int) (prop->fStart - commentStart); | 
 | 120 |                 if (commentLen > 0) { | 
 | 121 |                     SkASSERT(commentLen < 1000); | 
 | 122 |                     if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 123 |                         if (fReturnOnWrite) { | 
 | 124 |                             return true; | 
 | 125 |                         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 126 |                         this->lf(2); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 127 |                         wroteSomething = true; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 128 |                     } | 
 | 129 |                 } | 
 | 130 |                 size_t childSize = prop->fChildren.size(); | 
 | 131 |                 if (childSize) { | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 132 |                     if (MarkType::kLiteral == prop->fChildren[0]->fMarkType) { | 
 | 133 |                         SkASSERT(1 == childSize || 2 == childSize);  // incomplete | 
 | 134 |                         SkASSERT(1 == childSize || MarkType::kOutdent == prop->fChildren[1]->fMarkType); | 
 | 135 |                         commentStart = prop->fChildren[childSize - 1]->fContentStart; | 
 | 136 |                         literal = true; | 
 | 137 |                         literalOutdent = 2 == childSize && | 
 | 138 |                                 MarkType::kOutdent == prop->fChildren[1]->fMarkType; | 
 | 139 |                     } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 140 |                 } | 
 | 141 |                 commentLen = (int) (prop->fContentEnd - commentStart); | 
 | 142 |                 SkASSERT(commentLen > 0); | 
 | 143 |                 if (literal) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 144 |                     if (!fReturnOnWrite && !literalOutdent) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 145 |                         fIndent += 4; | 
 | 146 |                     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 147 |                     wroteSomething |= this->writeBlockIndent(commentLen, commentStart); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 148 |                     if (fReturnOnWrite) { | 
 | 149 |                         return true; | 
 | 150 |                     } | 
 | 151 |                     if (!fReturnOnWrite) { | 
 | 152 |                         this->lf(2); | 
 | 153 |                         if (!literalOutdent) { | 
 | 154 |                             fIndent -= 4; | 
 | 155 |                         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 156 |                     } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 157 |                     SkDEBUGCODE(wroteCode = true); | 
 | 158 |                 } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 159 |                 commentStart = prop->fTerminator; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 160 |                 } break; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 161 |             case MarkType::kBug: { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 162 |                 if (fReturnOnWrite) { | 
 | 163 |                     return true; | 
 | 164 |                 } | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 165 |                 string bugstr("(see skbug.com/" + string(prop->fContentStart, | 
 | 166 |                     prop->fContentEnd - prop->fContentStart) + ')'); | 
 | 167 |                 this->writeString(bugstr); | 
 | 168 |                 this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 169 |                 wroteSomething = true; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 170 |             } | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 171 |             case MarkType::kDeprecated: | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 172 |             case MarkType::kPrivate: | 
 | 173 |                 commentLen = (int) (prop->fStart - commentStart); | 
 | 174 |                 if (commentLen > 0) { | 
 | 175 |                     SkASSERT(commentLen < 1000); | 
 | 176 |                     if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 177 |                         if (fReturnOnWrite) { | 
 | 178 |                             return true; | 
 | 179 |                         } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 180 |                         this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 181 |                         wroteSomething = true; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 182 |                     } | 
 | 183 |                 } | 
 | 184 |                 commentStart = prop->fContentStart; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 185 |                 if (MarkType::kPrivate != prop->fMarkType && ' ' < commentStart[0]) { | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 186 |                     commentStart = strchr(commentStart, '\n'); | 
 | 187 |                 } | 
 | 188 |                 if (MarkType::kBug == prop->fMarkType) { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 189 |                     commentStart = prop->fContentEnd; | 
 | 190 |                 } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 191 |                 commentLen = (int) (prop->fContentEnd - commentStart); | 
 | 192 |                 if (commentLen > 0) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 193 |                     wroteSomething |= this->writeBlockIndent(commentLen, commentStart); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 194 |                     if (wroteSomething && fReturnOnWrite) { | 
 | 195 |                         return true; | 
 | 196 |                     } | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 197 |                     const char* end = commentStart + commentLen; | 
 | 198 |                     while (end > commentStart && ' ' == end[-1]) { | 
 | 199 |                         --end; | 
 | 200 |                     } | 
 | 201 |                     if (end > commentStart && '\n' == end[-1]) { | 
| Cary Clark | 61dfc3a | 2018-01-03 08:37:53 -0500 | [diff] [blame] | 202 |                         this->lfcr(); | 
 | 203 |                     } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 204 |                 } | 
 | 205 |                 commentStart = prop->fTerminator; | 
 | 206 |                 commentLen = (int) (def->fContentEnd - commentStart); | 
 | 207 |                 break; | 
 | 208 |             case MarkType::kExperimental: | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 209 |                 commentStart = prop->fContentStart; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 210 |                 if (' ' < commentStart[0]) { | 
 | 211 |                     commentStart = strchr(commentStart, '\n'); | 
 | 212 |                 } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 213 |                 commentLen = (int) (prop->fContentEnd - commentStart); | 
 | 214 |                 if (commentLen > 0) { | 
 | 215 |                     if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 216 |                         if (fReturnOnWrite) { | 
 | 217 |                             return true; | 
 | 218 |                         } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 219 |                         this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 220 |                         wroteSomething = true; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 221 |                     } | 
 | 222 |                 } | 
 | 223 |                 commentStart = prop->fTerminator; | 
 | 224 |                 commentLen = (int) (def->fContentEnd - commentStart); | 
 | 225 |                 break; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 226 |             case MarkType::kFormula: { | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 227 |                 commentLen = prop->fStart - commentStart; | 
 | 228 |                 if (commentLen > 0) { | 
 | 229 |                     if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 230 |                         if (fReturnOnWrite) { | 
 | 231 |                             return true; | 
 | 232 |                         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 233 |                         if (commentLen > 1 && '\n' == prop->fStart[-1] && | 
 | 234 |                                 '\n' == prop->fStart[-2]) { | 
 | 235 |                             this->lf(1); | 
 | 236 |                         } else { | 
 | 237 |                             this->writeSpace(); | 
 | 238 |                         } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 239 |                         wroteSomething = true; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 240 |                     } | 
 | 241 |                 } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 242 |                 int saveIndent = fIndent; | 
 | 243 |                 if (fIndent < fColumn + 1) { | 
 | 244 |                     fIndent = fColumn + 1; | 
 | 245 |                 } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 246 |                 wroteSomething |= this->writeBlockIndent(prop->length(), prop->fContentStart); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 247 |                 fIndent = saveIndent; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 248 |                 if (wroteSomething && fReturnOnWrite) { | 
 | 249 |                     return true; | 
 | 250 |                 } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 251 |                 commentStart = prop->fTerminator; | 
 | 252 |                 commentLen = (int) (def->fContentEnd - commentStart); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 253 |                 if (!fReturnOnWrite) { | 
 | 254 |                     if (commentLen > 1 && '\n' == commentStart[0] && '\n' == commentStart[1]) { | 
 | 255 |                         this->lf(2); | 
 | 256 |                     } else { | 
 | 257 |                         SkASSERT('\n' == prop->fTerminator[0]); | 
 | 258 |                         if ('.' != prop->fTerminator[1] && !fLinefeeds) { | 
 | 259 |                             this->writeSpace(); | 
 | 260 |                         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 261 |                     } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 262 |                 } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 263 |                 } break; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 264 |             case MarkType::kDetails: | 
| Cary Clark | ab2621d | 2018-01-30 10:08:57 -0500 | [diff] [blame] | 265 |             case MarkType::kIn: | 
 | 266 |             case MarkType::kLine: | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 267 |             case MarkType::kToDo: | 
 | 268 |                 commentLen = (int) (prop->fStart - commentStart); | 
 | 269 |                 if (commentLen > 0) { | 
 | 270 |                     SkASSERT(commentLen < 1000); | 
 | 271 |                     if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 272 |                         if (fReturnOnWrite) { | 
 | 273 |                             return true; | 
 | 274 |                         } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 275 |                         this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 276 |                         wroteSomething = true; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 277 |                     } | 
 | 278 |                 } | 
 | 279 |                 commentStart = prop->fTerminator; | 
 | 280 |                 commentLen = (int) (def->fContentEnd - commentStart); | 
 | 281 |                 break; | 
 | 282 |             case MarkType::kList: | 
 | 283 |                 commentLen = prop->fStart - commentStart; | 
 | 284 |                 if (commentLen > 0) { | 
 | 285 |                     if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, | 
 | 286 |                             Phrase::kNo)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 287 |                         if (fReturnOnWrite) { | 
 | 288 |                             return true; | 
 | 289 |                         } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 290 |                         this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 291 |                         wroteSomething = true; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 292 |                     } | 
 | 293 |                 } | 
 | 294 |                 for (auto row : prop->fChildren) { | 
 | 295 |                     SkASSERT(MarkType::kRow == row->fMarkType); | 
 | 296 |                     for (auto column : row->fChildren) { | 
 | 297 |                         SkASSERT(MarkType::kColumn == column->fMarkType); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 298 |                         if (fReturnOnWrite) { | 
 | 299 |                             return true; | 
 | 300 |                         } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 301 |                         this->writeString("-"); | 
 | 302 |                         this->writeSpace(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 303 |                         wroteSomething |= this->descriptionOut(column, SkipFirstLine::kNo, Phrase::kNo); | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 304 |                         this->lf(1); | 
 | 305 |                     } | 
 | 306 |                 } | 
 | 307 |                 commentStart = prop->fTerminator; | 
 | 308 |                 commentLen = (int) (def->fContentEnd - commentStart); | 
 | 309 |                 if ('\n' == commentStart[0] && '\n' == commentStart[1]) { | 
 | 310 |                     this->lf(2); | 
 | 311 |                 } | 
 | 312 |                 break; | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 313 |             case MarkType::kPhraseRef: { | 
 | 314 |                 commentLen = prop->fStart - commentStart; | 
 | 315 |                 if (commentLen > 0) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 316 |                     if (fReturnOnWrite) { | 
 | 317 |                         return true; | 
 | 318 |                     } | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 319 |                     this->rewriteBlock(commentLen, commentStart, Phrase::kNo); | 
 | 320 |                     // ince we don't do line wrapping, always insert LF before phrase | 
 | 321 |                     this->lfcr();   // TODO: remove this once rewriteBlock rewraps paragraphs | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 322 |                     wroteSomething = true; | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 323 |                 } | 
 | 324 |                 auto iter = fBmhParser->fPhraseMap.find(prop->fName); | 
 | 325 |                 if (fBmhParser->fPhraseMap.end() == iter) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 326 |                     return this->reportError<bool>("missing phrase definition"); | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 327 |                 } | 
 | 328 |                 Definition* phraseDef = iter->second; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 329 |                 // TODO: given TextParser(commentStart, prop->fStart + up to #) return if | 
 | 330 |                 // it ends with two of more linefeeds, ignoring other whitespace | 
 | 331 |                 Phrase defIsPhrase = '\n' == prop->fStart[0] && '\n' == prop->fStart[-1] ? | 
 | 332 |                         Phrase::kNo : Phrase::kYes; | 
 | 333 |                 if (Phrase::kNo == defIsPhrase) { | 
 | 334 |                     this->lf(2); | 
 | 335 |                 } | 
 | 336 |                 const char* start = phraseDef->fContentStart; | 
 | 337 |                 int length = phraseDef->length(); | 
 | 338 |                 auto propParams = prop->fChildren.begin(); | 
 | 339 |                 // can this share code or logic with mdout somehow? | 
 | 340 |                 for (auto child : phraseDef->fChildren) { | 
 | 341 |                     if (MarkType::kPhraseParam == child->fMarkType) { | 
 | 342 |                         continue; | 
 | 343 |                     } | 
 | 344 |                     int localLength = child->fStart - start; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 345 |                     if (fReturnOnWrite) { | 
 | 346 |                         return true; | 
 | 347 |                     } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 348 |                     this->rewriteBlock(localLength, start, defIsPhrase); | 
 | 349 |                     start += localLength; | 
 | 350 |                     length -= localLength; | 
 | 351 |                     SkASSERT(propParams != prop->fChildren.end()); | 
 | 352 |                     if (fColumn > 0) { | 
 | 353 |                         this->writeSpace(); | 
 | 354 |                     } | 
 | 355 |                     this->writeString((*propParams)->fName); | 
 | 356 |                     localLength = child->fContentEnd - child->fStart; | 
 | 357 |                     start += localLength; | 
 | 358 |                     length -= localLength; | 
 | 359 |                     if (isspace(start[0])) { | 
 | 360 |                         this->writeSpace(); | 
 | 361 |                     } | 
 | 362 |                     defIsPhrase = Phrase::kYes; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 363 |                     wroteSomething = true; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 364 |                 } | 
 | 365 |                 if (length > 0) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 366 |                     if (fReturnOnWrite) { | 
 | 367 |                         return true; | 
 | 368 |                     } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 369 |                     this->rewriteBlock(length, start, defIsPhrase); | 
 | 370 |                 } | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 371 |                 commentStart = prop->fContentStart; | 
 | 372 |                 commentLen = (int) (def->fContentEnd - commentStart); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 373 |                 if (!fReturnOnWrite) { | 
 | 374 |                     if ('\n' == commentStart[0] && '\n' == commentStart[1]) { | 
 | 375 |                         this->lf(2); | 
 | 376 |                     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 377 |                 } | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 378 |                 } break; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 379 |             default: | 
 | 380 |                 commentLen = (int) (prop->fStart - commentStart); | 
 | 381 |                 breakOut = true; | 
 | 382 |         } | 
 | 383 |         if (breakOut) { | 
 | 384 |             break; | 
 | 385 |         } | 
 | 386 |     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 387 |     if (!breakOut) { | 
 | 388 |         commentLen = (int) (def->fContentEnd - commentStart); | 
 | 389 |     } | 
| Cary Clark | 4855f78 | 2018-02-06 09:41:53 -0500 | [diff] [blame] | 390 |     SkASSERT(wroteCode || (commentLen > 0 && commentLen < 1500) || def->fDeprecated); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 391 |     if (commentLen > 0) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 392 |         if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, phrase)) { | 
 | 393 |             if (fReturnOnWrite) { | 
 | 394 |                 return true; | 
 | 395 |             } | 
 | 396 |             wroteSomething = true; | 
 | 397 |         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 398 |     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 399 |     SkASSERT(!fReturnOnWrite || !wroteSomething); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 400 |     return wroteSomething; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 401 | } | 
 | 402 |  | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 403 | void IncludeWriter::enumHeaderOut(RootDefinition* root, const Definition& child) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 404 |     const Definition* enumDef = nullptr; | 
 | 405 |     const char* bodyEnd = fDeferComment ? fDeferComment->fContentStart - 1 : | 
 | 406 |             child.fContentStart; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 407 |     this->firstBlockTrim((int) (bodyEnd - fStart), fStart);  // may write nothing | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 408 |     this->lf(2); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 409 |     this->indentDeferred(IndentKind::kEnumHeader); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 410 |     fDeferComment = nullptr; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 411 |     this->setStart(child.fContentStart, &child); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 412 |     const auto& nameDef = child.fTokens.front(); | 
 | 413 |     string fullName; | 
 | 414 |     if (nullptr != nameDef.fContentEnd) { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 415 |         TextParser enumClassCheck(&nameDef); | 
 | 416 |         const char* start = enumClassCheck.fStart; | 
 | 417 |         size_t len = (size_t) (enumClassCheck.fEnd - start); | 
 | 418 |         bool enumClass = enumClassCheck.skipExact("class "); | 
 | 419 |         if (enumClass) { | 
 | 420 |             start = enumClassCheck.fChar; | 
 | 421 |             const char* end = enumClassCheck.anyOf(" \n;{"); | 
 | 422 |             len = (size_t) (end - start); | 
 | 423 |         } | 
 | 424 |         string enumName(start, len); | 
 | 425 |         if (enumClass) { | 
 | 426 |             child.fChildren[0]->fName = enumName; | 
 | 427 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 428 |         fullName = root->fName + "::" + enumName; | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 429 |         enumDef = root->find(enumName, RootDefinition::AllowParens::kNo); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 430 |         if (!enumDef) { | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 431 |             enumDef = root->find(fullName, RootDefinition::AllowParens::kNo); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 432 |         } | 
| Cary Clark | 06c20f3 | 2018-03-20 15:53:27 -0400 | [diff] [blame] | 433 |         if (!enumDef) { | 
 | 434 |             auto mapEntry = fBmhParser->fEnumMap.find(enumName); | 
 | 435 |             if (fBmhParser->fEnumMap.end() != mapEntry) { | 
 | 436 |                 enumDef = &mapEntry->second; | 
 | 437 |             } | 
 | 438 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 439 |         SkASSERT(enumDef); | 
 | 440 |         // child[0] should be #Code comment starts at child[0].fTerminator | 
 | 441 |             // though skip until #Code is found (in case there's a #ToDo, etc) | 
 | 442 |         // child[1] should be #Const comment ends at child[1].fStart | 
 | 443 |         // comment becomes enum header (if any) | 
 | 444 |     } else { | 
 | 445 |         string enumName(root->fName); | 
 | 446 |         enumName += "::_anonymous"; | 
 | 447 |         if (fAnonymousEnumCount > 1) { | 
 | 448 |             enumName += '_' + to_string(fAnonymousEnumCount); | 
 | 449 |         } | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 450 |         enumDef = root->find(enumName, RootDefinition::AllowParens::kNo); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 451 |         SkASSERT(enumDef); | 
 | 452 |         ++fAnonymousEnumCount; | 
 | 453 |     } | 
 | 454 |     Definition* codeBlock = nullptr; | 
 | 455 |     const char* commentStart = nullptr; | 
 | 456 |     bool wroteHeader = false; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 457 |     bool lastAnchor = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 458 |     SkDEBUGCODE(bool foundConst = false); | 
 | 459 |     for (auto test : enumDef->fChildren) { | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 460 |         if (MarkType::kCode == test->fMarkType && !codeBlock) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 461 |             codeBlock = test; | 
 | 462 |             commentStart = codeBlock->fTerminator; | 
 | 463 |             continue; | 
 | 464 |         } | 
 | 465 |         if (!codeBlock) { | 
 | 466 |             continue; | 
 | 467 |         } | 
 | 468 |         const char* commentEnd = test->fStart; | 
 | 469 |         if (!wroteHeader && | 
 | 470 |                 !this->contentFree((int) (commentEnd - commentStart), commentStart)) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 471 |             if (fIndentNext) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 472 |                 // FIXME: how can I tell where fIdentNext gets cleared? | 
 | 473 |                 this->indentIn(IndentKind::kEnumChild); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 474 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 475 |             this->writeCommentHeader(); | 
 | 476 |             this->writeString("\\enum"); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 477 |             if (fullName.length() > 0) { | 
 | 478 |                 this->writeSpace(); | 
 | 479 |                 this->writeString(fullName.c_str()); | 
 | 480 |             } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 481 |             this->indentIn(IndentKind::kEnumChild2); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 482 |             this->lfcr(); | 
 | 483 |             wroteHeader = true; | 
 | 484 |         } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 485 |         if (lastAnchor) { | 
 | 486 |             if (commentEnd - commentStart > 1) { | 
 | 487 |                 SkASSERT('\n' == commentStart[0]); | 
 | 488 |                 if (' ' == commentStart[1]) { | 
 | 489 |                     this->writeSpace(); | 
 | 490 |                 } | 
 | 491 |             } | 
 | 492 |             lastAnchor = false; | 
 | 493 |         } | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 494 |         this->rewriteBlock((int) (commentEnd - commentStart), commentStart, Phrase::kNo); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 495 |         if (MarkType::kAnchor == test->fMarkType || MarkType::kCode == test->fMarkType) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 496 |             bool newLine = commentEnd - commentStart > 1 && | 
 | 497 |                 '\n' == commentEnd[-1] && '\n' == commentEnd[-2]; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 498 |             commentStart = test->fContentStart; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 499 |             commentEnd = MarkType::kAnchor == test->fMarkType ? test->fChildren[0]->fStart : | 
 | 500 |                     test->fContentEnd; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 501 |             if (newLine) { | 
 | 502 |                 this->lf(2); | 
 | 503 |             } else { | 
 | 504 |                 this->writeSpace(); | 
 | 505 |             } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 506 |             if (MarkType::kAnchor == test->fMarkType) { | 
 | 507 |                 this->rewriteBlock((int) (commentEnd - commentStart), commentStart, Phrase::kNo); | 
 | 508 |             } else { | 
 | 509 |                 this->writeBlock((int) (commentEnd - commentStart), commentStart); | 
 | 510 |                 this->lf(2); | 
 | 511 |             } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 512 |             lastAnchor = true;   // this->writeSpace(); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 513 |         } | 
 | 514 |         commentStart = test->fTerminator; | 
 | 515 |         if (MarkType::kConst == test->fMarkType) { | 
 | 516 |             SkASSERT(codeBlock);  // FIXME: check enum for correct order earlier | 
 | 517 |             SkDEBUGCODE(foundConst = true); | 
 | 518 |             break; | 
 | 519 |         } | 
 | 520 |     } | 
 | 521 |     SkASSERT(codeBlock); | 
 | 522 |     SkASSERT(foundConst); | 
 | 523 |     if (wroteHeader) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 524 |         this->indentOut(); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 525 |         this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 526 |         this->writeCommentTrailer(OneLine::kNo); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 527 |     } | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 528 |     Definition* braceHolder = child.fChildren[0]; | 
 | 529 |     if (KeyWord::kClass == braceHolder->fKeyWord) { | 
 | 530 |         braceHolder = braceHolder->fChildren[0]; | 
 | 531 |     } | 
 | 532 |     bodyEnd = braceHolder->fContentStart; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 533 |     SkASSERT('{' == bodyEnd[0]); | 
 | 534 |     ++bodyEnd; | 
 | 535 |     this->lfcr(); | 
 | 536 |     this->writeBlock((int) (bodyEnd - fStart), fStart); // write include "enum Name {" | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 537 |     this->indentIn(IndentKind::kEnumHeader2); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 538 |     this->singleLF(); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 539 |     this->setStart(bodyEnd, braceHolder); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 540 |     fEnumDef = enumDef; | 
 | 541 | } | 
 | 542 |  | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 543 | const Definition* IncludeWriter::enumMemberForComment(const Definition* currentEnumItem) const { | 
 | 544 |     for (auto constItem : currentEnumItem->fChildren) { | 
 | 545 |         if (MarkType::kLine == constItem->fMarkType | 
 | 546 |                 || MarkType::kExperimental == constItem->fMarkType | 
 | 547 |                 || MarkType::kDeprecated == constItem->fMarkType) { | 
 | 548 |             return constItem; | 
 | 549 |         } | 
 | 550 |     } | 
 | 551 |     SkASSERT(0); | 
 | 552 |     return nullptr; | 
 | 553 | } | 
 | 554 |  | 
 | 555 | string IncludeWriter::enumMemberComment(const Definition* currentEnumItem, | 
 | 556 |         const Definition& child) const { | 
 | 557 |     // #Const should always be followed by #Line, so description follows that | 
 | 558 |     string shortComment; | 
 | 559 |     for (auto constItem : currentEnumItem->fChildren) { | 
 | 560 |         if (MarkType::kLine == constItem->fMarkType) { | 
 | 561 |             shortComment = string(constItem->fContentStart, constItem->length()); | 
 | 562 |             break; | 
 | 563 |         } | 
 | 564 |         if (IncompleteAllowed(constItem->fMarkType)) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 565 |             shortComment = constItem->fParent->incompleteMessage(Definition::DetailsType::kPhrase); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 566 |         } | 
 | 567 |     } | 
 | 568 |     if (!shortComment.length()) { | 
 | 569 |         currentEnumItem->reportError<void>("missing #Line or #Deprecated or #Experimental"); | 
 | 570 |     } | 
 | 571 |     return shortComment; | 
 | 572 | } | 
 | 573 |  | 
 | 574 | IncludeWriter::ItemState IncludeWriter::enumMemberName( | 
 | 575 |         const Definition& child, const Definition* token, Item* item, LastItem* last, | 
 | 576 |         const Definition** currentEnumItem) { | 
 | 577 |     TextParser parser(fFileName, last->fStart, last->fEnd, fLineCount); | 
 | 578 |     parser.skipWhiteSpace(); | 
 | 579 |     item->fName = string(parser.fChar, (int) (last->fEnd - parser.fChar)); | 
 | 580 |     *currentEnumItem = this->matchMemberName(item->fName, child); | 
 | 581 |     if (token) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 582 |         this->setStart(token->fContentEnd, token); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 583 |         TextParser enumLine(token->fFileName, last->fEnd, token->fContentStart, token->fLineCount); | 
 | 584 |         const char* end = enumLine.anyOf(",}="); | 
 | 585 |         SkASSERT(end); | 
 | 586 |         if ('=' == *end) {  // write enum value | 
 | 587 |             last->fEnd = token->fContentEnd; | 
 | 588 |             item->fValue = string(token->fContentStart, (int) (last->fEnd - token->fContentStart)); | 
 | 589 |             return ItemState::kValue; | 
 | 590 |         } | 
 | 591 |     } | 
 | 592 |     return ItemState::kComment; | 
 | 593 | } | 
 | 594 |  | 
 | 595 | void IncludeWriter::enumMemberOut(const Definition* currentEnumItem, const Definition& child, | 
 | 596 |         const Item& item, Preprocessor& preprocessor) { | 
 | 597 |     SkASSERT(currentEnumItem); | 
 | 598 |     string shortComment = this->enumMemberComment(currentEnumItem, child); | 
 | 599 |     int enumItemValueTab = | 
 | 600 |             SkTMax((int) item.fName.length() + fIndent + 1, fEnumItemValueTab); // 1: , | 
 | 601 |     int valueLength = item.fValue.length(); | 
 | 602 |     int assignLength = valueLength ? valueLength + 3 : 0; // 3: space = space | 
 | 603 |     int enumItemCommentTab = SkTMax(enumItemValueTab + assignLength, fEnumItemCommentTab); | 
 | 604 |     int trimNeeded = enumItemCommentTab + shortComment.length() - (100 - (sizeof("//!< ") - 1)); | 
 | 605 |     bool crAfterName = false; | 
 | 606 |     if (trimNeeded > 0) { | 
 | 607 |         if (item.fValue.length()) { | 
 | 608 |             int valueSpare = SkTMin(trimNeeded,                  // 3 below: space = space | 
 | 609 |                     (int) (enumItemCommentTab - enumItemValueTab - item.fValue.length() - 3)); | 
 | 610 |             SkASSERT(valueSpare >= 0); | 
 | 611 |             trimNeeded -= valueSpare; | 
 | 612 |             enumItemCommentTab -= valueSpare; | 
 | 613 |         } | 
 | 614 |         if (trimNeeded > 0) { | 
 | 615 |             int nameSpare = SkTMin(trimNeeded, (int) (enumItemValueTab - item.fName.length() | 
 | 616 |                     - fIndent - 1));  // 1: , | 
 | 617 |             SkASSERT(nameSpare >= 0); | 
 | 618 |             trimNeeded -= nameSpare; | 
 | 619 |             enumItemValueTab -= nameSpare; | 
 | 620 |             enumItemCommentTab -= nameSpare; | 
 | 621 |         } | 
 | 622 |         if (trimNeeded > 0) { | 
 | 623 |             crAfterName = true; | 
 | 624 |             if (!valueLength) { | 
 | 625 |                 this->enumMemberForComment(currentEnumItem)->reportError<void>("comment too long"); | 
 | 626 |             } else if (valueLength + fIndent + 8 + shortComment.length() > // 8: addtional indent | 
 | 627 |                     100 - (sizeof(", //!< ") - 1)) { // -1: zero-terminated string | 
 | 628 |                 this->enumMemberForComment(currentEnumItem)->reportError<void>("comment 2 long"); | 
 | 629 |             }                                    // 2: = space | 
 | 630 |             enumItemValueTab = fEnumItemValueTab +  2                 // 2: , space | 
 | 631 |                     - SkTMax(0, fEnumItemValueTab + 2 + valueLength +    2 - fEnumItemCommentTab); | 
 | 632 |             enumItemCommentTab = SkTMax(enumItemValueTab + valueLength + 2, fEnumItemCommentTab); | 
 | 633 |         } | 
 | 634 |     } | 
 | 635 |     this->lfcr(); | 
 | 636 |     this->writeString(item.fName); | 
 | 637 |     int saveIndent = fIndent; | 
 | 638 |     if (item.fValue.length()) { | 
 | 639 |         if (!crAfterName) { | 
 | 640 |             this->indentToColumn(enumItemValueTab); | 
 | 641 |         } else { | 
 | 642 |             this->writeSpace(); | 
 | 643 |         } | 
 | 644 |         this->writeString("="); | 
 | 645 |         if (crAfterName) { | 
 | 646 |             this->lfcr(); | 
 | 647 |             fIndent = enumItemValueTab; | 
 | 648 |         } else { | 
 | 649 |             this->writeSpace(); | 
 | 650 |         } | 
 | 651 |         this->writeString(item.fValue); | 
 | 652 |     } | 
 | 653 |     this->writeString(","); | 
 | 654 |     this->indentToColumn(enumItemCommentTab); | 
 | 655 |     this->writeString("//!<"); | 
 | 656 |     this->writeSpace(); | 
 | 657 |     this->rewriteBlock(shortComment.length(), shortComment.c_str(), Phrase::kYes); | 
 | 658 |     this->lfcr(); | 
 | 659 |     fIndent = saveIndent; | 
 | 660 |     if (preprocessor.fStart) { | 
 | 661 |         SkASSERT(preprocessor.fEnd); | 
 | 662 |         int saveIndent = fIndent; | 
 | 663 |         fIndent = SkTMax(0, fIndent - 8); | 
 | 664 |         this->lf(2); | 
 | 665 |         this->writeBlock( | 
 | 666 |                 (int) (preprocessor.fEnd - preprocessor.fStart), preprocessor.fStart); | 
 | 667 |         this->lfcr(); | 
 | 668 |         fIndent = saveIndent; | 
 | 669 |         preprocessor.reset(); | 
 | 670 |     } | 
 | 671 | } | 
 | 672 |  | 
 | 673 | // iterate through include tokens and find how much remains for 1 line comments | 
 | 674 | // put ones that fit on same line, ones that are too big wrap | 
 | 675 | void IncludeWriter::enumMembersOut(Definition& child) { | 
 | 676 |     ItemState state = ItemState::kNone; | 
 | 677 |     const Definition* currentEnumItem; | 
 | 678 |     LastItem last = { nullptr, nullptr }; | 
 | 679 |     auto brace = child.fChildren[0]; | 
 | 680 |     if (KeyWord::kClass == brace->fKeyWord) { | 
 | 681 |         brace = brace->fChildren[0]; | 
 | 682 |     } | 
 | 683 |     SkASSERT(Bracket::kBrace == brace->fBracket); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 684 |     vector<IterState> iterStack; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 685 |     iterStack.emplace_back(brace->fTokens.begin(), brace->fTokens.end()); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 686 |     IterState* iterState = &iterStack[0]; | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 687 |     Preprocessor preprocessor; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 688 |     Item item; | 
 | 689 |     while (iterState->fDefIter != iterState->fDefEnd) { | 
 | 690 |         auto& token = *iterState->fDefIter++; | 
 | 691 |         if (this->enumPreprocessor(&token, MemberPass::kOut, iterStack, &iterState, | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 692 |                 &preprocessor)) { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 693 |             continue; | 
 | 694 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 695 |         if (ItemState::kName == state) { | 
 | 696 |             state = this->enumMemberName(child, &token, &item, &last, ¤tEnumItem); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 697 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 698 |         if (ItemState::kValue == state) { | 
 | 699 |             TextParser valueEnd(token.fFileName, last.fEnd, token.fContentStart, token.fLineCount); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 700 |             const char* end = valueEnd.anyOf(",}"); | 
 | 701 |             if (!end) {  // write expression continuation | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 702 |                 item.fValue += string(last.fEnd, (int) (token.fContentEnd - last.fEnd)); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 703 |                 continue; | 
 | 704 |             } | 
 | 705 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 706 |         if (ItemState::kNone != state) { | 
 | 707 |             this->enumMemberOut(currentEnumItem, child, item, preprocessor); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 708 |             item.reset(); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 709 |             this->setStartBack(token.fContentStart, &token); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 710 |             state = ItemState::kNone; | 
 | 711 |             last.fStart = nullptr; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 712 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 713 |         SkASSERT(ItemState::kNone == state); | 
 | 714 |         if (!last.fStart) { | 
 | 715 |             last.fStart = fStart; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 716 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 717 |         last.fEnd = token.fContentEnd; | 
 | 718 |         state = ItemState::kName; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 719 |     } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 720 |     if (ItemState::kName == state) { | 
 | 721 |         state = this->enumMemberName(child, nullptr, &item, &last, ¤tEnumItem); | 
 | 722 |     } | 
 | 723 |     if (ItemState::kValue == state || ItemState::kComment == state) { | 
 | 724 |         this->enumMemberOut(currentEnumItem, child, item, preprocessor); | 
 | 725 |     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 726 |     this->indentOut(); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 727 | } | 
 | 728 |  | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 729 | bool IncludeWriter::enumPreprocessor(Definition* token, MemberPass pass, | 
 | 730 |         vector<IterState>& iterStack, IterState** iterState, Preprocessor* preprocessor) { | 
 | 731 |     if (token && Definition::Type::kBracket == token->fType) { | 
 | 732 |         if (Bracket::kSlashSlash == token->fBracket) { | 
 | 733 |             if (MemberPass::kOut == pass) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 734 |                 this->setStart(token->fContentEnd, token); | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 735 |             } | 
 | 736 |             return true;  // ignore old inline comments | 
 | 737 |         } | 
 | 738 |         if (Bracket::kSlashStar == token->fBracket) { | 
 | 739 |             if (MemberPass::kOut == pass) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 740 |                 this->setStart(token->fContentEnd + 1, token); | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 741 |             } | 
 | 742 |             return true;  // ignore old inline comments | 
 | 743 |         } | 
 | 744 |         if (Bracket::kPound == token->fBracket) {  // preprocessor wraps member | 
| Cary Clark | a4f581a | 2018-04-03 15:31:59 -0400 | [diff] [blame] | 745 |             preprocessor->fDefinition = token; | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 746 |             preprocessor->fStart = token->fContentStart; | 
 | 747 |             if (KeyWord::kIf == token->fKeyWord || KeyWord::kIfdef == token->fKeyWord) { | 
 | 748 |                 iterStack.emplace_back(token->fTokens.begin(), token->fTokens.end()); | 
 | 749 |                 *iterState = &iterStack.back(); | 
 | 750 |                 preprocessor->fWord = true; | 
 | 751 |             } else if (KeyWord::kEndif == token->fKeyWord || KeyWord::kElif == token->fKeyWord | 
 | 752 |                     || KeyWord::kElse == token->fKeyWord) { | 
 | 753 |                 iterStack.pop_back(); | 
 | 754 |                 *iterState = &iterStack.back(); | 
 | 755 |                 preprocessor->fEnd = token->fContentEnd; | 
 | 756 |                 if (KeyWord::kElif == token->fKeyWord) { | 
 | 757 |                     iterStack.emplace_back(token->fTokens.begin(), token->fTokens.end()); | 
 | 758 |                     *iterState = &iterStack.back(); | 
 | 759 |                     preprocessor->fWord = true; | 
 | 760 |                 } | 
 | 761 |             } else { | 
 | 762 |                 SkASSERT(0); // incomplete | 
 | 763 |             } | 
 | 764 |             return true; | 
 | 765 |         } | 
| Cary Clark | a4f581a | 2018-04-03 15:31:59 -0400 | [diff] [blame] | 766 |         if (preprocessor->fDefinition) { | 
 | 767 |             if (Bracket::kParen == token->fBracket) { | 
 | 768 |                 preprocessor->fEnd = token->fContentEnd; | 
 | 769 |                 SkASSERT(')' == *preprocessor->fEnd); | 
 | 770 |                 ++preprocessor->fEnd; | 
 | 771 |                 return true; | 
 | 772 |             } | 
 | 773 |             SkASSERT(0);  // incomplete | 
 | 774 |         } | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 775 |         return true; | 
 | 776 |     } | 
 | 777 |     if (token && Definition::Type::kWord != token->fType) { | 
 | 778 |         SkASSERT(0); // incomplete | 
 | 779 |     } | 
 | 780 |     if (preprocessor->fWord) { | 
 | 781 |         preprocessor->fWord = false; | 
 | 782 |         preprocessor->fEnd = token->fContentEnd; | 
 | 783 |         return true; | 
 | 784 |     } | 
 | 785 |     return false; | 
 | 786 | } | 
 | 787 |  | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 788 | void IncludeWriter::enumSizeItems(const Definition& child) { | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 789 |     ItemState state = ItemState::kNone; | 
 | 790 |     ItemLength lengths = { 0, 0, 0, 0 }; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 791 |     const char* lastEnd = nullptr; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 792 |     auto brace = child.fChildren[0]; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 793 |     if (KeyWord::kClass == brace->fKeyWord) { | 
 | 794 |         brace = brace->fChildren[0]; | 
 | 795 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 796 |     SkASSERT(Bracket::kBrace == brace->fBracket); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 797 |     vector<IterState> iterStack; | 
 | 798 |     iterStack.emplace_back(brace->fTokens.begin(), brace->fTokens.end()); | 
 | 799 |     IterState* iterState = &iterStack[0]; | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 800 |     Preprocessor preprocessor; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 801 |     string enumName; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 802 |     while (iterState->fDefIter != iterState->fDefEnd) { | 
 | 803 |         auto& token = *iterState->fDefIter++; | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 804 |         if (this->enumPreprocessor(&token, MemberPass::kCount, iterStack, &iterState, | 
 | 805 |                 &preprocessor)) { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 806 |             continue; | 
 | 807 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 808 |         if (ItemState::kName == state) { | 
 | 809 |             TextParser enumLine(token.fFileName, lastEnd, token.fContentStart, token.fLineCount); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 810 |             const char* end = enumLine.anyOf(",}="); | 
 | 811 |             SkASSERT(end); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 812 |             state = '=' == *end ? ItemState::kValue : ItemState::kComment; | 
 | 813 |             if (ItemState::kValue == state) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 814 |                 lastEnd = token.fContentEnd; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 815 |                 lengths.fCurValue = (int) (lastEnd - token.fContentStart); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 816 |                 continue; | 
 | 817 |             } | 
 | 818 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 819 |         if (ItemState::kValue == state) { | 
 | 820 |             TextParser valueEnd(token.fFileName, lastEnd, token.fContentStart, token.fLineCount); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 821 |             const char* end = valueEnd.anyOf(",}"); | 
 | 822 |             if (!end) {  // write expression continuation | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 823 |                 lengths.fCurValue += (int) (token.fContentEnd - lastEnd); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 824 |                 continue; | 
 | 825 |             } | 
 | 826 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 827 |         if (ItemState::kNone != state) { | 
 | 828 |             this->checkEnumLengths(child, enumName, &lengths); | 
 | 829 |             lengths.fCurValue = 0; | 
 | 830 |             state = ItemState::kNone; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 831 |         } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 832 |         SkASSERT(ItemState::kNone == state); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 833 |         lastEnd = token.fContentEnd; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 834 |         lengths.fCurName = (int) (lastEnd - token.fContentStart); | 
 | 835 |         enumName = string(token.fContentStart, lengths.fCurName); | 
 | 836 |         state = ItemState::kName; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 837 |     } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 838 |     if (ItemState::kNone != state) { | 
 | 839 |         this->checkEnumLengths(child, enumName, &lengths); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 840 |     } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 841 |     fEnumItemValueTab = lengths.fLongestName + fIndent + 1 /* 1: , */ ; | 
 | 842 |     if (lengths.fLongestValue) { | 
 | 843 |         lengths.fLongestValue += 3; // 3: space = space | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 844 |     } | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 845 |     fEnumItemCommentTab = fEnumItemValueTab + lengths.fLongestValue + 1 ; // 1: space before //!< | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 846 |     // iterate through bmh children and see which comments fit on include lines | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 847 |     if (!this->checkChildCommentLength(fEnumDef, MarkType::kConst)) { | 
 | 848 |         fEnumDef->reportError<void>("expected at least one #Const in #Enum"); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 849 |     } | 
 | 850 | } | 
 | 851 |  | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 852 | const Definition* IncludeWriter::matchMemberName(string matchName, const Definition& child) const { | 
 | 853 |     const Definition* parent = &child; | 
 | 854 |     if (KeyWord::kEnum == child.fKeyWord && child.fChildren.size() > 0 | 
 | 855 |             && KeyWord::kClass == child.fChildren[0]->fKeyWord) { | 
 | 856 |         matchName = child.fChildren[0]->fName + "::" + matchName; | 
 | 857 |     } | 
 | 858 |     do { | 
 | 859 |         if (KeyWord::kStruct == parent->fKeyWord || KeyWord::kClass == parent->fKeyWord) { | 
 | 860 |             matchName = parent->fName + "::" + matchName; | 
 | 861 |         } | 
 | 862 |     } while ((parent = parent->fParent)); | 
 | 863 |     const Definition* enumItem = nullptr; | 
 | 864 |     for (auto testItem : fEnumDef->fChildren) { | 
 | 865 |         if (MarkType::kConst != testItem->fMarkType) { | 
 | 866 |             continue; | 
 | 867 |         } | 
 | 868 |         if (matchName != testItem->fName) { | 
 | 869 |             continue; | 
 | 870 |         } | 
 | 871 |         enumItem = testItem; | 
 | 872 |         break; | 
 | 873 |     } | 
 | 874 |     SkASSERT(enumItem); | 
 | 875 |     return enumItem; | 
 | 876 | } | 
 | 877 |  | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 878 | // walk children and output complete method doxygen description | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 879 | void IncludeWriter::methodOut(Definition* method, const Definition& child) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 880 |     if (fPendingMethod) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 881 |         this->indentOut(); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 882 |         fPendingMethod = false; | 
 | 883 |     } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 884 |     fBmhMethod = method; | 
 | 885 |     fMethodDef = &child; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 886 |     fContinuation = nullptr; | 
 | 887 |     fDeferComment = nullptr; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 888 |     Definition* csParent = method->csParent(); | 
| Cary Clark | a4f581a | 2018-04-03 15:31:59 -0400 | [diff] [blame] | 889 |     if (csParent && (0 == fIndent || fIndentNext)) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 890 |         this->indentIn(IndentKind::kMethodOut); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 891 |         fIndentNext = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 892 |     } | 
 | 893 |     this->writeCommentHeader(); | 
 | 894 |     fIndent += 4; | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 895 |     this->descriptionOut(method, SkipFirstLine::kNo, Phrase::kNo); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 896 |     // compute indention column | 
 | 897 |     size_t column = 0; | 
 | 898 |     bool hasParmReturn = false; | 
 | 899 |     for (auto methodPart : method->fChildren) { | 
 | 900 |         if (MarkType::kParam == methodPart->fMarkType) { | 
 | 901 |             column = SkTMax(column, methodPart->fName.length()); | 
 | 902 |             hasParmReturn = true; | 
 | 903 |         } else if (MarkType::kReturn == methodPart->fMarkType) { | 
 | 904 |             hasParmReturn = true; | 
 | 905 |         } | 
 | 906 |     } | 
 | 907 |     if (hasParmReturn) { | 
 | 908 |         this->lf(2); | 
 | 909 |         column += fIndent + sizeof("@return "); | 
 | 910 |         int saveIndent = fIndent; | 
 | 911 |         for (auto methodPart : method->fChildren) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 912 |             if (MarkType::kParam == methodPart->fMarkType) { | 
 | 913 |                 this->writeString("@param"); | 
 | 914 |                 this->writeSpace(); | 
 | 915 |                 this->writeString(methodPart->fName.c_str()); | 
 | 916 |             } else if (MarkType::kReturn == methodPart->fMarkType) { | 
 | 917 |                 this->writeString("@return"); | 
 | 918 |             } else { | 
 | 919 |                 continue; | 
 | 920 |             } | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 921 |             this->indentToColumn(column); | 
 | 922 |             fIndent = column; | 
| Cary Clark | 1a8d762 | 2018-03-05 13:26:16 -0500 | [diff] [blame] | 923 |             this->descriptionOut(methodPart, SkipFirstLine::kNo, Phrase::kYes); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 924 |             fIndent = saveIndent; | 
 | 925 |             this->lfcr(); | 
 | 926 |         } | 
 | 927 |     } else { | 
 | 928 |         this->lfcr(); | 
 | 929 |     } | 
 | 930 |     fIndent -= 4; | 
 | 931 |     this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 932 |     this->writeCommentTrailer(OneLine::kNo); | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 933 |     fBmhMethod = nullptr; | 
 | 934 |     fMethodDef = nullptr; | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 935 |     fEnumDef = nullptr; | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 936 |     fWroteMethod = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 937 | } | 
 | 938 |  | 
 | 939 | void IncludeWriter::structOut(const Definition* root, const Definition& child, | 
 | 940 |         const char* commentStart, const char* commentEnd) { | 
 | 941 |     this->writeCommentHeader(); | 
 | 942 |     this->writeString("\\"); | 
 | 943 |     SkASSERT(MarkType::kClass == child.fMarkType || MarkType::kStruct == child.fMarkType); | 
 | 944 |     this->writeString(MarkType::kClass == child.fMarkType ? "class" : "struct"); | 
 | 945 |     this->writeSpace(); | 
 | 946 |     this->writeString(child.fName.c_str()); | 
 | 947 |     fIndent += 4; | 
 | 948 |     this->lfcr(); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 949 |     if (child.fDeprecated) { | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 950 |         this->writeString(child.incompleteMessage(Definition::DetailsType::kSentence)); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 951 |     } else { | 
 | 952 |         this->rewriteBlock((int)(commentEnd - commentStart), commentStart, Phrase::kNo); | 
 | 953 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 954 |     fIndent -= 4; | 
 | 955 |     this->lfcr(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 956 |     this->writeCommentTrailer(OneLine::kNo); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 957 | } | 
 | 958 |  | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 959 | bool IncludeWriter::findEnumSubtopic(string undername, const Definition** rootDefPtr) const { | 
 | 960 |     const Definition* subtopic = fEnumDef->fParent; | 
 | 961 |     string subcheck = subtopic->fFiddle + '_' + undername; | 
 | 962 |     auto iter = fBmhParser->fTopicMap.find(subcheck); | 
 | 963 |     if (iter == fBmhParser->fTopicMap.end()) { | 
 | 964 |         return false; | 
 | 965 |     } | 
 | 966 |     *rootDefPtr = iter->second; | 
 | 967 |     return true; | 
 | 968 | } | 
 | 969 |  | 
| Cary Clark | 2dc84ad | 2018-01-26 12:56:22 -0500 | [diff] [blame] | 970 | Definition* IncludeWriter::findMemberCommentBlock(const vector<Definition*>& bmhChildren, | 
| Cary Clark | 2d4bf5f | 2018-04-16 08:37:38 -0400 | [diff] [blame] | 971 |         string name) const { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 972 |     for (auto memberDef : bmhChildren) { | 
 | 973 |         if (MarkType::kMember != memberDef->fMarkType) { | 
 | 974 |             continue; | 
 | 975 |         } | 
 | 976 |         string match = memberDef->fName; | 
 | 977 |         // if match.endsWith(name) ... | 
| Cary Clark | 300cc5b | 2018-02-20 12:50:35 -0500 | [diff] [blame] | 978 |         if (match.length() >= name.length() && | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 979 |                 0 == match.compare(match.length() - name.length(), name.length(), name)) { | 
 | 980 |             return memberDef; | 
 | 981 |         } | 
 | 982 |     } | 
 | 983 |     for (auto memberDef : bmhChildren) { | 
 | 984 |         if (MarkType::kSubtopic != memberDef->fMarkType && MarkType::kTopic != memberDef->fMarkType) { | 
 | 985 |             continue; | 
 | 986 |         } | 
 | 987 |         Definition* result = this->findMemberCommentBlock(memberDef->fChildren, name); | 
 | 988 |         if (result) { | 
 | 989 |             return result; | 
 | 990 |         } | 
 | 991 |     } | 
 | 992 |     return nullptr; | 
| Cary Clark | 2dc84ad | 2018-01-26 12:56:22 -0500 | [diff] [blame] | 993 | } | 
 | 994 |  | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 995 | Definition* IncludeWriter::findMethod(string name, RootDefinition* root) const { | 
 | 996 |     if (root) { | 
 | 997 |         return root->find(name, RootDefinition::AllowParens::kNo); | 
 | 998 |     } | 
 | 999 |     auto methodIter = fBmhParser->fMethodMap.find(name); | 
 | 1000 |     if (fBmhParser->fMethodMap.end() == methodIter) { | 
 | 1001 |         return nullptr; | 
 | 1002 |     } | 
 | 1003 |     return &methodIter->second; | 
 | 1004 | } | 
 | 1005 |  | 
 | 1006 |  | 
 | 1007 | void IncludeWriter::firstBlock(int size, const char* data) { | 
 | 1008 |      SkAssertResult(this->firstBlockTrim(size, data)); | 
 | 1009 | } | 
 | 1010 |  | 
 | 1011 | bool IncludeWriter::firstBlockTrim(int size, const char* data) { | 
 | 1012 |     bool result = this->writeBlockTrim(size, data); | 
 | 1013 |     if (fFirstWrite) { | 
 | 1014 |         auto fileInfo = std::find_if(fRootTopic->fChildren.begin(), fRootTopic->fChildren.end(), | 
 | 1015 |                 [](const Definition* def){ return MarkType::kFile == def->fMarkType; } ); | 
 | 1016 |         if (fRootTopic->fChildren.end() != fileInfo) { | 
 | 1017 |             this->writeCommentHeader(); | 
 | 1018 |             this->writeString("\\file"); | 
 | 1019 |             this->writeSpace(); | 
 | 1020 |             size_t lastSlash = fFileName.rfind('/'); | 
 | 1021 |             if (string::npos == lastSlash) { | 
 | 1022 |                 lastSlash = fFileName.rfind('\\'); | 
 | 1023 |             } | 
 | 1024 |             string fileName = fFileName.substr(lastSlash + 1); | 
 | 1025 |             this->writeString(fileName); | 
 | 1026 |             this->lf(2); | 
 | 1027 |             fIndent += 4; | 
 | 1028 |             this->descriptionOut(*fileInfo, SkipFirstLine::kNo, Phrase::kNo); | 
 | 1029 |             fIndent -= 4; | 
 | 1030 |             this->writeCommentTrailer(OneLine::kNo); | 
 | 1031 |         } | 
 | 1032 |         fFirstWrite = false; | 
 | 1033 |     } | 
 | 1034 |     return result; | 
 | 1035 | } | 
 | 1036 |  | 
 | 1037 | void IncludeWriter::setStart(const char* start, const Definition* def) { | 
 | 1038 |     SkASSERT(start >= fStart); | 
 | 1039 |     this->setStartBack(start, def); | 
 | 1040 | } | 
 | 1041 |  | 
 | 1042 | void IncludeWriter::setStartBack(const char* start, const Definition* def) { | 
 | 1043 |     fStartSetter = def; | 
 | 1044 |     fStart = start; | 
 | 1045 | } | 
 | 1046 |  | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1047 | Definition* IncludeWriter::structMemberOut(const Definition* memberStart, const Definition& child) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1048 |     const char* blockStart = !fWroteMethod && fDeferComment ? fDeferComment->fContentEnd : fStart; | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1049 |     const char* blockEnd = fWroteMethod && fDeferComment ? fDeferComment->fStart - 1 : | 
 | 1050 |             memberStart->fStart; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1051 |     this->firstBlockTrim((int) (blockEnd - blockStart), blockStart); | 
 | 1052 |     this->indentDeferred(IndentKind::kStructMember); | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1053 |     fWroteMethod = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1054 |     string name(child.fContentStart, (int) (child.fContentEnd - child.fContentStart)); | 
| Cary Clark | 2dc84ad | 2018-01-26 12:56:22 -0500 | [diff] [blame] | 1055 |     Definition* commentBlock = this->findMemberCommentBlock(fBmhStructDef->fChildren, name); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1056 |     if (!commentBlock) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1057 |         return memberStart->reportError<Definition*>("member missing comment block 2"); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1058 |     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1059 |     auto lineIter = std::find_if(commentBlock->fChildren.begin(), commentBlock->fChildren.end(), | 
 | 1060 |         [](const Definition* def){ return MarkType::kLine == def->fMarkType; } ); | 
 | 1061 |     SkASSERT(commentBlock->fChildren.end() != lineIter); | 
 | 1062 |     const Definition* lineDef = *lineIter; | 
 | 1063 |     if (fStructMemberLength > 100) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1064 |         this->writeCommentHeader(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1065 |         this->writeSpace(); | 
 | 1066 |         this->rewriteBlock(lineDef->length(), lineDef->fContentStart, Phrase::kYes); | 
 | 1067 |         this->writeCommentTrailer(OneLine::kYes); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1068 |     } | 
 | 1069 |     this->lfcr(); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1070 |     this->writeBlock((int) (child.fStart - memberStart->fContentStart), | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1071 |             memberStart->fContentStart); | 
 | 1072 |     this->indentToColumn(fStructMemberTab); | 
 | 1073 |     this->writeString(name.c_str()); | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 1074 |     auto tokenIter = child.fParent->fTokens.begin(); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1075 |     std::advance(tokenIter, child.fParentIndex + 1); | 
 | 1076 |     Definition* valueStart = &*tokenIter; | 
 | 1077 |     while (Definition::Type::kPunctuation != tokenIter->fType) { | 
 | 1078 |         std::advance(tokenIter, 1); | 
 | 1079 |         SkASSERT(child.fParent->fTokens.end() != tokenIter); | 
 | 1080 |     } | 
 | 1081 |     Definition* valueEnd = &*tokenIter; | 
 | 1082 |     if (valueStart != valueEnd) { | 
 | 1083 |         this->indentToColumn(fStructValueTab); | 
 | 1084 |         this->writeString("="); | 
 | 1085 |         this->writeSpace(); | 
 | 1086 |         this->writeBlock((int) (valueEnd->fStart - valueStart->fContentStart), | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 1087 |                 valueStart->fContentStart); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1088 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1089 |     this->writeString(";"); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1090 |     if (fStructMemberLength <= 100) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1091 |         this->indentToColumn(fStructCommentTab); | 
 | 1092 |         this->writeString("//!<"); | 
 | 1093 |         this->writeSpace(); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1094 |         this->rewriteBlock(lineDef->length(), lineDef->fContentStart, Phrase::kYes); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1095 |     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1096 |     this->lf(1); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1097 |     return valueEnd; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1098 | } | 
 | 1099 |  | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1100 | // const and constexpr and #define aren't contained in a braces like struct and enum. | 
 | 1101 | // use a bmh subtopic to group like ones together, then measure them in the include as if | 
 | 1102 | // they were formally linked together | 
 | 1103 | void IncludeWriter::constSizeMembers(const RootDefinition* root) { | 
 | 1104 |     // fBmhConst->fParent is subtopic containing all grouped const expressions | 
 | 1105 |     // fConstDef is token of const include name, hopefully on same line as const start | 
 | 1106 |     string rootPrefix = root ? root->fName + "::" : ""; | 
 | 1107 |     const Definition* test = fConstDef; | 
 | 1108 |     int tokenIndex = test->fParentIndex; | 
 | 1109 |     int longestName = 0; | 
 | 1110 |     int longestValue = 0; | 
 | 1111 |     int longestComment = 0; | 
 | 1112 |     const Definition* subtopic = fBmhConst->fParent; | 
 | 1113 |     SkASSERT(subtopic); | 
 | 1114 |     SkASSERT(MarkType::kSubtopic == subtopic->fMarkType); | 
 | 1115 |     // back up to first token on line | 
 | 1116 |     size_t lineCount = test->fLineCount; | 
 | 1117 |     const Definition* last; | 
 | 1118 |     auto tokenIter = test->fParent->fTokens.begin(); | 
 | 1119 |     std::advance(tokenIter, tokenIndex); | 
 | 1120 |     do { | 
 | 1121 |         last = test; | 
 | 1122 |         std::advance(tokenIter, -1); | 
 | 1123 |         test = &*tokenIter; | 
 | 1124 |         SkASSERT(test->fParentIndex == --tokenIndex); | 
 | 1125 |     } while (lineCount == test->fLineCount); | 
 | 1126 |     test = last; | 
 | 1127 |     for (auto child : subtopic->fChildren) { | 
 | 1128 |         if (MarkType::kConst != child->fMarkType) { | 
 | 1129 |             continue; | 
 | 1130 |         } | 
 | 1131 |         // expect found name to be on the left of assign | 
 | 1132 |         // expect assign | 
 | 1133 |         // expect semicolon | 
 | 1134 |         // no parens, no braces | 
 | 1135 |         while (rootPrefix + test->fName != child->fName) { | 
 | 1136 |             std::advance(tokenIter, 1); | 
 | 1137 |             test = &*tokenIter; | 
 | 1138 |             SkASSERT(lineCount >= test->fLineCount); | 
 | 1139 |         } | 
 | 1140 |         ++lineCount; | 
 | 1141 |         TextParser constText(test); | 
 | 1142 |         const char* nameEnd = constText.trimmedBracketEnd('='); | 
 | 1143 |         SkAssertResult(constText.skipToEndBracket('=')); | 
 | 1144 |         const char* valueEnd = constText.trimmedBracketEnd(';'); | 
 | 1145 |         auto lineIter = std::find_if(child->fChildren.begin(), child->fChildren.end(), | 
 | 1146 |                 [](const Definition* def){ return MarkType::kLine == def->fMarkType; }); | 
 | 1147 |         SkASSERT(child->fChildren.end() != lineIter); | 
 | 1148 |         longestName = SkTMax(longestName, (int) (nameEnd - constText.fStart)); | 
 | 1149 |         longestValue = SkTMax(longestValue, (int) (valueEnd - constText.fChar)); | 
 | 1150 |         longestComment = SkTMax(longestComment, (*lineIter)->length()); | 
 | 1151 |     } | 
 | 1152 |     // write fStructValueTab, fStructCommentTab | 
 | 1153 |     fConstValueTab = longestName + fIndent + 1; | 
 | 1154 |     fConstCommentTab = fConstValueTab + longestValue + 2; | 
 | 1155 |     fConstLength = fConstCommentTab + longestComment + (int) sizeof("//!<"); | 
 | 1156 | } | 
 | 1157 |  | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 1158 | bool IncludeWriter::defineOut(const Definition& def) { | 
 | 1159 |     if (def.fTokens.size() < 1) { | 
 | 1160 |         return false; | 
 | 1161 |     } | 
 | 1162 |     auto& child = def.fTokens.front(); | 
 | 1163 |     string name(child.fContentStart, child.length()); | 
 | 1164 |     auto defIter = fBmhParser->fDefineMap.find(name); | 
 | 1165 |     if (fBmhParser->fDefineMap.end() == defIter) { | 
 | 1166 |         return false; | 
 | 1167 |     } | 
 | 1168 |     const Definition& bmhDef = defIter->second; | 
 | 1169 |     this->constOut(&def, &bmhDef); | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 1170 |     return true; | 
 | 1171 | } | 
 | 1172 |  | 
| Cary Clark | 884dd7d | 2017-10-11 10:37:52 -0400 | [diff] [blame] | 1173 | void IncludeWriter::structSizeMembers(const Definition& child) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1174 |     int longestType = 0; | 
 | 1175 |     Definition* typeStart = nullptr; | 
 | 1176 |     int longestName = 0; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1177 |     int longestValue = 0; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1178 |     int longestComment = 0; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1179 |     SkASSERT(child.fChildren.size() == 1 || child.fChildren.size() == 2); | 
 | 1180 |     bool inEnum = false; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1181 |     bool inMethod = false; | 
 | 1182 |     bool inMember = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1183 |     auto brace = child.fChildren[0]; | 
 | 1184 |     SkASSERT(Bracket::kBrace == brace->fBracket); | 
 | 1185 |     for (auto& token : brace->fTokens) { | 
 | 1186 |         if (Definition::Type::kBracket == token.fType) { | 
 | 1187 |             if (Bracket::kSlashSlash == token.fBracket) { | 
 | 1188 |                 continue;  // ignore old inline comments | 
 | 1189 |             } | 
 | 1190 |             if (Bracket::kSlashStar == token.fBracket) { | 
 | 1191 |                 continue;  // ignore old inline comments | 
 | 1192 |             } | 
 | 1193 |             if (Bracket::kParen == token.fBracket) { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1194 |                 if (inMethod) { | 
 | 1195 |                     continue; | 
 | 1196 |                 } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1197 |                 break; | 
 | 1198 |             } | 
 | 1199 |             SkASSERT(0); // incomplete | 
 | 1200 |         } | 
 | 1201 |         if (Definition::Type::kKeyWord == token.fType) { | 
 | 1202 |             switch (token.fKeyWord) { | 
 | 1203 |                 case KeyWord::kEnum: | 
 | 1204 |                     inEnum = true; | 
 | 1205 |                     break; | 
 | 1206 |                 case KeyWord::kConst: | 
 | 1207 |                 case KeyWord::kConstExpr: | 
 | 1208 |                 case KeyWord::kStatic: | 
 | 1209 |                 case KeyWord::kInt: | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1210 |                 case KeyWord::kUint8_t: | 
 | 1211 |                 case KeyWord::kUint16_t: | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1212 |                 case KeyWord::kUint32_t: | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1213 |                 case KeyWord::kUint64_t: | 
| Cary Clark | 4dc5a45 | 2018-05-21 11:56:57 -0400 | [diff] [blame] | 1214 |                 case KeyWord::kUintPtr_t: | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1215 |                 case KeyWord::kSize_t: | 
 | 1216 |                 case KeyWord::kFloat: | 
 | 1217 |                 case KeyWord::kBool: | 
 | 1218 |                 case KeyWord::kVoid: | 
 | 1219 |                     if (!typeStart) { | 
 | 1220 |                         typeStart = &token; | 
 | 1221 |                     } | 
 | 1222 |                     break; | 
 | 1223 |                 default: | 
 | 1224 |                     break; | 
 | 1225 |             } | 
 | 1226 |             continue; | 
 | 1227 |         } | 
 | 1228 |         if (Definition::Type::kPunctuation == token.fType) { | 
 | 1229 |             if (inEnum) { | 
 | 1230 |                 SkASSERT(Punctuation::kSemicolon == token.fPunctuation); | 
 | 1231 |                 inEnum = false; | 
 | 1232 |             } | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1233 |             if (inMethod) { | 
 | 1234 |                 if (Punctuation::kColon == token.fPunctuation) { | 
 | 1235 |                     inMethod = false; | 
 | 1236 |                 } else if (Punctuation::kLeftBrace == token.fPunctuation) { | 
 | 1237 |                     inMethod = false; | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1238 |                 } else if (Punctuation::kSemicolon == token.fPunctuation) { | 
 | 1239 |                     inMethod = false; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1240 |                 } else { | 
 | 1241 |                     SkASSERT(0);  // incomplete | 
 | 1242 |                 } | 
 | 1243 |             } | 
 | 1244 |             if (inMember) { | 
 | 1245 |                 SkASSERT(Punctuation::kSemicolon == token.fPunctuation); | 
 | 1246 |                 typeStart = nullptr; | 
 | 1247 |                 inMember = false; | 
 | 1248 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1249 |             continue; | 
 | 1250 |         } | 
 | 1251 |         if (Definition::Type::kWord != token.fType) { | 
 | 1252 |             SkASSERT(0); // incomplete | 
 | 1253 |         } | 
 | 1254 |         if (MarkType::kMember == token.fMarkType) { | 
 | 1255 |             TextParser typeStr(token.fFileName, typeStart->fContentStart, token.fContentStart, | 
 | 1256 |                     token.fLineCount); | 
 | 1257 |             typeStr.trimEnd(); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1258 |             longestType = SkTMax(longestType, (int) (typeStr.fEnd - typeStr.fStart)); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1259 |             longestName = SkTMax(longestName, (int) (token.fContentEnd - token.fContentStart)); | 
 | 1260 |             typeStart->fMemberStart = true; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1261 |             inMember = true; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1262 |             string tokenName(token.fContentStart, (int) (token.fContentEnd - token.fContentStart)); | 
 | 1263 |             Definition* commentBlock = this->findMemberCommentBlock(fBmhStructDef->fChildren, | 
 | 1264 |                     tokenName); | 
 | 1265 |             if (!commentBlock) { | 
 | 1266 |                 return token.reportError<void>("member missing comment block 1"); | 
 | 1267 |             } | 
 | 1268 |             auto lineIter = std::find_if(commentBlock->fChildren.begin(), | 
 | 1269 |                     commentBlock->fChildren.end(), | 
 | 1270 |                     [](const Definition* def){ return MarkType::kLine == def->fMarkType; } ); | 
 | 1271 |             SkASSERT(commentBlock->fChildren.end() != lineIter); | 
 | 1272 |             const Definition* lineDef = *lineIter; | 
 | 1273 |             longestComment = SkTMax(longestComment, lineDef->length()); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1274 |             continue; | 
 | 1275 |         } | 
 | 1276 |         if (MarkType::kMethod == token.fMarkType) { | 
 | 1277 |             inMethod = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1278 |             continue; | 
 | 1279 |         } | 
 | 1280 |         SkASSERT(MarkType::kNone == token.fMarkType); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1281 |         if (typeStart) { | 
 | 1282 |             if (inMember) { | 
 | 1283 |                 longestValue = | 
 | 1284 |                         SkTMax(longestValue, (int) (token.fContentEnd - token.fContentStart)); | 
 | 1285 |             } | 
 | 1286 |         } else { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1287 |             typeStart = &token; | 
 | 1288 |         } | 
 | 1289 |     } | 
 | 1290 |     fStructMemberTab = longestType + fIndent + 1 /* space before name */ ; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1291 |     fStructValueTab = fStructMemberTab + longestName + 2 /* space ; */ ; | 
 | 1292 |     fStructCommentTab = fStructValueTab; | 
 | 1293 |     if (longestValue) { | 
 | 1294 |         fStructCommentTab += longestValue + 3 /* space = space */ ; | 
 | 1295 |         fStructValueTab -= 1 /* ; */ ; | 
 | 1296 |     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1297 |     fStructMemberLength = fStructCommentTab + longestComment; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 1298 |     // iterate through struct to ensure that members' comments fit on line | 
 | 1299 |     // struct or class may not have any members | 
 | 1300 |     (void) this->checkChildCommentLength(fBmhStructDef, MarkType::kMember); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1301 | } | 
 | 1302 |  | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1303 | static bool find_start(const Definition* startDef, const char* start) { | 
 | 1304 |     for (const auto& child : startDef->fTokens) { | 
 | 1305 |         if (child.fContentStart == start) { | 
 | 1306 |             return MarkType::kMethod == child.fMarkType; | 
 | 1307 |         } | 
 | 1308 |         if (child.fContentStart >= start) { | 
 | 1309 |             break; | 
 | 1310 |         } | 
 | 1311 |         if (find_start(&child, start)) { | 
 | 1312 |             return true; | 
 | 1313 |         } | 
 | 1314 |     } | 
 | 1315 |     return false; | 
 | 1316 | } | 
 | 1317 |  | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1318 | bool IncludeWriter::populate(Definition* def, ParentPair* prevPair, RootDefinition* root) { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1319 |     if (!def->fTokens.size()) { | 
 | 1320 |         return true; | 
 | 1321 |     } | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1322 |     ParentPair pair = { def, prevPair }; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1323 |     // write bulk of original include up to class, method, enum, etc., excepting preceding comment | 
 | 1324 |     // find associated bmh object | 
 | 1325 |     // write any associated comments in Doxygen form | 
 | 1326 |     // skip include comment | 
 | 1327 |     // if there is a series of same named methods, write one set of comments, then write all methods | 
 | 1328 |     string methodName; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 1329 |     Definition* method = nullptr; | 
 | 1330 |     Definition* clonedMethod = nullptr; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1331 |     const Definition* memberStart = nullptr; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1332 |     const Definition* memberEnd = nullptr; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1333 |     fContinuation = nullptr; | 
 | 1334 |     bool inStruct = false; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1335 |     bool inConstructor = false; | 
| Cary Clark | 884dd7d | 2017-10-11 10:37:52 -0400 | [diff] [blame] | 1336 |     bool inInline = false; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1337 |     bool eatOperator = false; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1338 |     bool sawConst = false; | 
 | 1339 |     bool staticOnly = false; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1340 |     bool sawTypedef = false; | 
| Cary Clark | 27dddae | 2018-06-08 15:57:37 -0400 | [diff] [blame] | 1341 |     Definition* deferredTypedefComment = nullptr; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1342 |     const Definition* requireDense = nullptr; | 
 | 1343 |     const Definition* startDef = nullptr; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1344 |     for (auto& child : def->fTokens) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1345 |         if (KeyWord::kInline == child.fKeyWord) { | 
 | 1346 |             continue; | 
 | 1347 |         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1348 |         if (KeyWord::kOperator == child.fKeyWord && method && | 
 | 1349 |                 Definition::MethodType::kOperator == method->fMethodType) { | 
 | 1350 |             eatOperator = true; | 
 | 1351 |             continue; | 
 | 1352 |         } | 
 | 1353 |         if (eatOperator) { | 
 | 1354 |             if (Bracket::kSquare == child.fBracket || Bracket::kParen == child.fBracket) { | 
 | 1355 |                 continue; | 
 | 1356 |             } | 
 | 1357 |             eatOperator = false; | 
 | 1358 |             fContinuation = nullptr; | 
 | 1359 |             if (KeyWord::kConst == child.fKeyWord) { | 
 | 1360 |                 continue; | 
 | 1361 |             } | 
 | 1362 |         } | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1363 |         if (memberEnd) { | 
 | 1364 |             if (memberEnd != &child) { | 
 | 1365 |                 continue; | 
 | 1366 |             } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1367 |             startDef = &child; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1368 |             this->setStart(child.fContentStart + 1, &child); | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1369 |             memberEnd = nullptr; | 
 | 1370 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1371 |         if (child.fPrivate) { | 
| Cary Clark | 884dd7d | 2017-10-11 10:37:52 -0400 | [diff] [blame] | 1372 |             if (MarkType::kMethod == child.fMarkType) { | 
 | 1373 |                 inInline = true; | 
 | 1374 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1375 |             continue; | 
 | 1376 |         } | 
| Cary Clark | 884dd7d | 2017-10-11 10:37:52 -0400 | [diff] [blame] | 1377 |         if (inInline) { | 
 | 1378 |             if (Definition::Type::kKeyWord == child.fType) { | 
 | 1379 |                 SkASSERT(MarkType::kMethod != child.fMarkType); | 
 | 1380 |                 continue; | 
 | 1381 |             } | 
 | 1382 |             if (Definition::Type::kPunctuation == child.fType) { | 
 | 1383 |                 if (Punctuation::kLeftBrace == child.fPunctuation) { | 
 | 1384 |                     inInline = false; | 
 | 1385 |                 } else { | 
 | 1386 |                     SkASSERT(Punctuation::kAsterisk == child.fPunctuation); | 
 | 1387 |                 } | 
 | 1388 |                 continue; | 
 | 1389 |             } | 
 | 1390 |             if (Definition::Type::kWord == child.fType) { | 
 | 1391 |                 string name(child.fContentStart, child.fContentEnd - child.fContentStart); | 
 | 1392 |                 SkASSERT(string::npos != name.find("::")); | 
 | 1393 |                 continue; | 
 | 1394 |             } | 
 | 1395 |             if (Definition::Type::kBracket == child.fType) { | 
 | 1396 |                 SkASSERT(Bracket::kParen == child.fBracket); | 
 | 1397 |                 continue; | 
 | 1398 |             } | 
 | 1399 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1400 |         if (fContinuation) { | 
 | 1401 |             if (Definition::Type::kKeyWord == child.fType) { | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1402 |                 if (KeyWord::kFriend == child.fKeyWord || | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1403 |                         KeyWord::kSK_API == child.fKeyWord) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1404 |                     continue; | 
 | 1405 |                 } | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1406 |                 const IncludeKey& includeKey = kKeyWords[(int) child.fKeyWord]; | 
 | 1407 |                 if (KeyProperty::kNumber == includeKey.fProperty) { | 
 | 1408 |                     continue; | 
 | 1409 |                 } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1410 |             } | 
| Cary Clark | 3cd22cc | 2017-12-01 11:49:58 -0500 | [diff] [blame] | 1411 |             if (Definition::Type::kBracket == child.fType) { | 
 | 1412 |                 if (Bracket::kAngle == child.fBracket) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1413 |                     continue; | 
 | 1414 |                 } | 
| Cary Clark | 3cd22cc | 2017-12-01 11:49:58 -0500 | [diff] [blame] | 1415 |                 if (Bracket::kParen == child.fBracket) { | 
 | 1416 |                     if (!clonedMethod) { | 
 | 1417 |                         if (inConstructor) { | 
 | 1418 |                             fContinuation = child.fContentStart; | 
 | 1419 |                         } | 
 | 1420 |                         continue; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1421 |                     } | 
| Cary Clark | 3cd22cc | 2017-12-01 11:49:58 -0500 | [diff] [blame] | 1422 |                     int alternate = 1; | 
 | 1423 |                     ptrdiff_t childLen = child.fContentEnd - child.fContentStart; | 
 | 1424 |                     SkASSERT(')' == child.fContentStart[childLen]); | 
 | 1425 |                     ++childLen; | 
 | 1426 |                     do { | 
 | 1427 |                         TextParser params(clonedMethod->fFileName, clonedMethod->fStart, | 
 | 1428 |                             clonedMethod->fContentStart, clonedMethod->fLineCount); | 
 | 1429 |                         params.skipToEndBracket('('); | 
 | 1430 |                         if (params.startsWith(child.fContentStart, childLen)) { | 
 | 1431 |                             this->methodOut(clonedMethod, child); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1432 |                             sawConst = false; | 
| Cary Clark | 3cd22cc | 2017-12-01 11:49:58 -0500 | [diff] [blame] | 1433 |                             break; | 
 | 1434 |                         } | 
 | 1435 |                         ++alternate; | 
 | 1436 |                         string alternateMethod = methodName + '_' + to_string(alternate); | 
| Cary Clark | 224c700 | 2018-06-27 11:00:21 -0400 | [diff] [blame^] | 1437 |                        clonedMethod = this->findMethod(alternateMethod, root); | 
| Cary Clark | 3cd22cc | 2017-12-01 11:49:58 -0500 | [diff] [blame] | 1438 |                     } while (clonedMethod); | 
 | 1439 |                     if (!clonedMethod) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1440 |                         return child.reportError<bool>("cloned method not found"); | 
| Cary Clark | 3cd22cc | 2017-12-01 11:49:58 -0500 | [diff] [blame] | 1441 |                     } | 
 | 1442 |                     clonedMethod = nullptr; | 
 | 1443 |                     continue; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1444 |                 } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1445 |             } | 
 | 1446 |             if (Definition::Type::kWord == child.fType) { | 
 | 1447 |                 if (clonedMethod) { | 
 | 1448 |                     continue; | 
 | 1449 |                 } | 
 | 1450 |                 size_t len = (size_t) (child.fContentEnd - child.fContentStart); | 
 | 1451 |                 const char operatorStr[] = "operator"; | 
 | 1452 |                 size_t operatorLen = sizeof(operatorStr) - 1; | 
 | 1453 |                 if (len >= operatorLen && !strncmp(child.fContentStart, operatorStr, operatorLen)) { | 
 | 1454 |                     fContinuation = child.fContentEnd; | 
 | 1455 |                     continue; | 
 | 1456 |                 } | 
 | 1457 |             } | 
 | 1458 |             if (Definition::Type::kPunctuation == child.fType && | 
 | 1459 |                     (Punctuation::kSemicolon == child.fPunctuation || | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 1460 |                     Punctuation::kLeftBrace == child.fPunctuation || | 
 | 1461 |                     (Punctuation::kColon == child.fPunctuation && inConstructor))) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1462 |                 SkASSERT(fContinuation[0] == '('); | 
 | 1463 |                 const char* continueEnd = child.fContentStart; | 
 | 1464 |                 while (continueEnd > fContinuation && isspace(continueEnd[-1])) { | 
 | 1465 |                     --continueEnd; | 
 | 1466 |                 } | 
 | 1467 |                 methodName += string(fContinuation, continueEnd - fContinuation); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1468 |                 method = this->findMethod(methodName, root); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1469 |                 if (!method) { | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1470 |                     if (fBmhStructDef && fBmhStructDef->fDeprecated) { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1471 |                         fContinuation = nullptr; | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1472 |                         continue; | 
 | 1473 |                     } | 
| Cary Clark | 06c20f3 | 2018-03-20 15:53:27 -0400 | [diff] [blame] | 1474 |                     return child.reportError<bool>("method not found"); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1475 |                 } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 1476 |                 this->methodOut(method, child); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1477 |                 sawConst = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1478 |                 continue; | 
 | 1479 |             } | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1480 |             if (Definition::Type::kPunctuation == child.fType && | 
 | 1481 |                     Punctuation::kAsterisk == child.fPunctuation && | 
 | 1482 |                     clonedMethod) { | 
 | 1483 |                 continue; | 
 | 1484 |             } | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1485 |             if (inConstructor) { | 
 | 1486 |                 continue; | 
 | 1487 |             } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1488 |             method = this->findMethod(methodName + "()", root); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1489 |             if (method) { | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 1490 |                 if (method->fCloned) { | 
 | 1491 |                     clonedMethod = method; | 
 | 1492 |                     continue; | 
 | 1493 |                 } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 1494 |                 this->methodOut(method, child); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1495 |                 sawConst = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1496 |                 continue; | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1497 |             } else if (fBmhStructDef && fBmhStructDef->fDeprecated) { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1498 |                 fContinuation = nullptr; | 
 | 1499 |                 continue; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1500 |             } | 
| Cary Clark | 06c20f3 | 2018-03-20 15:53:27 -0400 | [diff] [blame] | 1501 |             return child.reportError<bool>("method not found"); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1502 |         } | 
 | 1503 |         if (Bracket::kSlashSlash == child.fBracket || Bracket::kSlashStar == child.fBracket) { | 
 | 1504 |             if (!fDeferComment) { | 
 | 1505 |                 fDeferComment = &child; | 
 | 1506 |             } | 
 | 1507 |             continue; | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 1508 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1509 |         if (MarkType::kMethod == child.fMarkType) { | 
| Cary Clark | 2d4bf5f | 2018-04-16 08:37:38 -0400 | [diff] [blame] | 1510 |             if (this->isInternalName(child)) { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1511 |                 continue; | 
 | 1512 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1513 |             const char* bodyEnd = fDeferComment ? fDeferComment->fContentStart - 1 : | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1514 |                     fAttrDeprecated ? fAttrDeprecated->fContentStart - 1 : | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1515 |                     child.fContentStart; | 
| Cary Clark | 7cfcbca | 2018-01-04 16:11:51 -0500 | [diff] [blame] | 1516 |             if (Definition::Type::kBracket == def->fType && Bracket::kDebugCode == def->fBracket) { | 
 | 1517 |                 auto tokenIter = def->fParent->fTokens.begin(); | 
 | 1518 |                 std::advance(tokenIter, def->fParentIndex - 1); | 
 | 1519 |                 Definition* prior = &*tokenIter; | 
 | 1520 |                 if (Definition::Type::kBracket == def->fType && | 
 | 1521 |                         Bracket::kSlashStar == prior->fBracket) { | 
 | 1522 |                     bodyEnd = prior->fContentStart - 1; | 
 | 1523 |                 } | 
 | 1524 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1525 |             // FIXME: roll end-trimming into writeBlockTrim call | 
 | 1526 |             while (fStart < bodyEnd && ' ' >= bodyEnd[-1]) { | 
 | 1527 |                 --bodyEnd; | 
 | 1528 |             } | 
 | 1529 |             int blockSize = (int) (bodyEnd - fStart); | 
| Cary Clark | 2d4bf5f | 2018-04-16 08:37:38 -0400 | [diff] [blame] | 1530 |             SkASSERT(blockSize >= 0); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1531 |             if (blockSize) { | 
| Cary Clark | 7cfcbca | 2018-01-04 16:11:51 -0500 | [diff] [blame] | 1532 |                 string debugstr(fStart, blockSize); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1533 |                 this->writeBlock(blockSize, fStart); | 
 | 1534 |             } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1535 |             startDef = &child; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1536 |             this->setStart(child.fContentStart, &child); | 
| Cary Clark | 06c20f3 | 2018-03-20 15:53:27 -0400 | [diff] [blame] | 1537 |             auto mapFind = fBmhParser->fMethodMap.find(child.fName); | 
 | 1538 |             if (fBmhParser->fMethodMap.end() != mapFind) { | 
 | 1539 |                 inConstructor = false; | 
 | 1540 |                 method = &mapFind->second; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1541 |                 methodName = child.fName; | 
| Cary Clark | 06c20f3 | 2018-03-20 15:53:27 -0400 | [diff] [blame] | 1542 |             } else { | 
 | 1543 |                 methodName = root->fName + "::" + child.fName; | 
| Cary Clark | 224c700 | 2018-06-27 11:00:21 -0400 | [diff] [blame^] | 1544 |                 size_t lastName = root->fName.rfind(':'); | 
 | 1545 |                 lastName = string::npos == lastName ? 0 : lastName + 1; | 
 | 1546 |                 inConstructor = root->fName.substr(lastName) == child.fName; | 
| Cary Clark | 06c20f3 | 2018-03-20 15:53:27 -0400 | [diff] [blame] | 1547 |                 method = root->find(methodName, RootDefinition::AllowParens::kNo); | 
 | 1548 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1549 |             fContinuation = child.fContentEnd; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1550 |             if (!method) { | 
 | 1551 |                 continue; | 
 | 1552 |             } | 
 | 1553 |             if (method->fCloned) { | 
 | 1554 |                 clonedMethod = method; | 
 | 1555 |                 continue; | 
 | 1556 |             } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 1557 |             this->methodOut(method, child); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1558 |             sawConst = false; | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1559 |             if (fAttrDeprecated) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1560 |                 startDef = fAttrDeprecated; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1561 |                 this->setStartBack(fAttrDeprecated->fContentStart, fAttrDeprecated); | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1562 |                 fAttrDeprecated = nullptr; | 
 | 1563 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1564 |             continue; | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 1565 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1566 |         if (Definition::Type::kKeyWord == child.fType) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1567 |             switch (child.fKeyWord) { | 
 | 1568 |                 case KeyWord::kStruct: | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1569 |                 case KeyWord::kClass: | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1570 |                     fICSStack.push_back(&child); | 
 | 1571 |                     fStructEnded = false; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1572 |                     fStructMemberTab = 0; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1573 |                     // if struct contains members, compute their name and comment tabs | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1574 |                     if (child.fChildren.size() > 0) { | 
 | 1575 |                         const ParentPair* testPair = &pair; | 
 | 1576 |                         while ((testPair = testPair->fPrev)) { | 
 | 1577 |                             if (KeyWord::kClass == testPair->fParent->fKeyWord) { | 
 | 1578 |                                 inStruct = fInStruct = true; | 
 | 1579 |                                 break; | 
 | 1580 |                             } | 
 | 1581 |                         } | 
 | 1582 |                     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1583 |                     if (fInStruct) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1584 |                         // try child; root+child; root->parent+child; etc. | 
 | 1585 |                         int trial = 0; | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 1586 |                         RootDefinition* search = root; | 
 | 1587 |                         Definition* parent = search->fParent; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1588 |                         do { | 
 | 1589 |                             string name; | 
 | 1590 |                             if (0 == trial) { | 
 | 1591 |                                 name = child.fName; | 
 | 1592 |                             } else if (1 == trial) { | 
 | 1593 |                                 name = root->fName + "::" + child.fName; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1594 |                             } else if (2 == trial) { | 
 | 1595 |                                 name = root->fName; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1596 |                             } else { | 
 | 1597 |                                 SkASSERT(parent); | 
 | 1598 |                                 name = parent->fName + "::" + child.fName; | 
 | 1599 |                                 search = parent->asRoot(); | 
 | 1600 |                                 parent = search->fParent; | 
 | 1601 |                             } | 
 | 1602 |                             fBmhStructDef = search->find(name, RootDefinition::AllowParens::kNo); | 
 | 1603 |                         } while (!fBmhStructDef && ++trial); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 1604 |                         root = fBmhStructDef->asRoot(); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1605 |                         SkASSERT(root); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1606 |                         fIndent += 4; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1607 |                         this->structSizeMembers(child); | 
 | 1608 |                         fIndent -= 4; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1609 |                         SkASSERT(!fIndentNext); | 
 | 1610 |                         fIndentNext = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1611 |                     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1612 |                     if (child.fChildren.size() > 0) { | 
 | 1613 |                         const char* bodyEnd = fDeferComment ? fDeferComment->fContentStart - 1 : | 
 | 1614 |                                 child.fContentStart; | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1615 |                         this->writeBlockTrim((int) (bodyEnd - fStart), fStart); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1616 |                         if (fPendingMethod) { | 
| Cary Clark | 27dddae | 2018-06-08 15:57:37 -0400 | [diff] [blame] | 1617 |                             if (fIndent >= 4) { | 
 | 1618 |                                 this->indentOut(); | 
 | 1619 |                             } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1620 |                             fPendingMethod = false; | 
 | 1621 |                         } | 
 | 1622 |                         startDef = requireDense ? requireDense : &child; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1623 |                         if (requireDense) { | 
 | 1624 |                             startDef = requireDense; | 
 | 1625 |                             this->setStart(requireDense->fContentStart, requireDense); | 
 | 1626 |                         } else { | 
 | 1627 |                             startDef = &child; | 
 | 1628 |                             this->setStart(child.fContentStart, &child); | 
 | 1629 |                         } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1630 |                         requireDense = nullptr; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1631 |                         if (!fInStruct && (!root || child.fName != root->fName)) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1632 |                             root = &fBmhParser->fClassMap[child.fName]; | 
 | 1633 |                             fRootTopic = root->fParent; | 
 | 1634 |                             SkASSERT(!root->fVisited); | 
 | 1635 |                             root->clearVisited(); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1636 | #if 0 | 
 | 1637 |     // this seems better balanced; but real problem is probably fInStruct | 
 | 1638 |                             if (fIndentStack.size() > 0) { | 
 | 1639 |                                 this->indentOut(); | 
 | 1640 |                             } | 
 | 1641 |                             SkASSERT(!fIndent); | 
 | 1642 | #else | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1643 |                             fIndent = 0; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1644 | #endif | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1645 |                             fBmhStructDef = root; | 
 | 1646 |                         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1647 |                         if (child.fName == root->fName) { | 
 | 1648 |                             if (Definition* parent = root->fParent) { | 
 | 1649 |                                 if (MarkType::kTopic == parent->fMarkType || | 
 | 1650 |                                         MarkType::kSubtopic == parent->fMarkType) { | 
| Cary Clark | e4aa371 | 2017-09-15 02:56:12 -0400 | [diff] [blame] | 1651 |                                     const char* commentStart = root->fContentStart; | 
 | 1652 |                                     const char* commentEnd = root->fChildren[0]->fStart; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1653 |                                     this->structOut(root, *root, commentStart, commentEnd); | 
 | 1654 |                                 } else { | 
 | 1655 |                                     SkASSERT(0); // incomplete | 
 | 1656 |                                 } | 
 | 1657 |                             } else { | 
 | 1658 |                                 SkASSERT(0); // incomplete | 
 | 1659 |                             } | 
 | 1660 |                         } else { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1661 |                             SkASSERT(fInStruct); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1662 |                             Definition* priorBlock = fBmhStructDef; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1663 |                             Definition* codeBlock = nullptr; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1664 |                             Definition* nextBlock = nullptr; | 
 | 1665 |                             for (auto test : fBmhStructDef->fChildren) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1666 |                                 if (MarkType::kCode == test->fMarkType) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1667 |                                     SkASSERT(!codeBlock);  // FIXME: check enum earlier | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1668 |                                     codeBlock = test; | 
 | 1669 |                                     continue; | 
 | 1670 |                                 } | 
 | 1671 |                                 if (codeBlock) { | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1672 |                                     nextBlock = test; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1673 |                                     break; | 
 | 1674 |                                 } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1675 |                                 priorBlock = test; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1676 |                             } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1677 |                       // FIXME: trigger error earlier if inner #Struct or #Class is missing #Code | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1678 |                             if (!fBmhStructDef->fDeprecated) { | 
 | 1679 |                                 SkASSERT(codeBlock); | 
 | 1680 |                                 SkASSERT(nextBlock);  // FIXME: check enum for correct order earlier | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 1681 |                                 const char* commentStart = codeBlock->fTerminator; | 
 | 1682 |                                 const char* commentEnd = nextBlock->fStart; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1683 |                       // FIXME: trigger error if #Code is present but comment is before it earlier | 
 | 1684 |                                 SkASSERT(priorBlock); // code always preceded by #Line (I think) | 
 | 1685 |                                 TextParser priorComment(priorBlock->fFileName, | 
 | 1686 |                                         priorBlock->fTerminator, codeBlock->fStart, | 
 | 1687 |                                         priorBlock->fLineCount); | 
 | 1688 |                                 priorComment.trimEnd(); | 
 | 1689 |                                 if (!priorComment.eof()) { | 
 | 1690 |                                     return priorBlock->reportError<bool>( | 
 | 1691 |                                             "expect no comment before #Code"); | 
 | 1692 |                                 } | 
 | 1693 |                                 TextParser nextComment(codeBlock->fFileName, commentStart, | 
 | 1694 |                                         commentEnd, codeBlock->fLineCount); | 
 | 1695 |                                 nextComment.trimEnd(); | 
 | 1696 |                                 if (!priorComment.eof()) { | 
 | 1697 |                                     return priorBlock->reportError<bool>( | 
 | 1698 |                                             "expect comment after #Code"); | 
 | 1699 |                                 } | 
 | 1700 |                                 if (!nextComment.eof()) { | 
 | 1701 |  | 
 | 1702 |                                 } | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 1703 |                                 fIndentNext = true; | 
 | 1704 |                                 this->structOut(root, *fBmhStructDef, commentStart, commentEnd); | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1705 |                             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1706 |                         } | 
 | 1707 |                         fDeferComment = nullptr; | 
 | 1708 |                     } else { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1709 |                        // empty forward reference | 
 | 1710 |                         bool writeTwo = '\n' == child.fContentStart[-1] | 
 | 1711 |                                 && '\n' == child.fContentStart[-2]; | 
 | 1712 |                         if (writeTwo) { | 
 | 1713 |                             const char* bodyEnd = fDeferComment ? fDeferComment->fContentStart - 1 : | 
 | 1714 |                                     child.fContentStart; | 
 | 1715 |                             this->writeBlockTrim((int) (bodyEnd - fStart), fStart); | 
 | 1716 |                             this->lf(writeTwo ? 2 : 1); | 
 | 1717 |                             fIndent = 0; | 
 | 1718 |                             this->writeBlockTrim(child.length() + 1, child.fContentStart); | 
 | 1719 |                             writeTwo = '\n' == child.fContentEnd[1] | 
 | 1720 |                                     && '\n' == child.fContentStart[2]; | 
 | 1721 |                             this->lf(writeTwo ? 2 : 1); | 
 | 1722 |                             fStart = child.fContentEnd + 1; | 
 | 1723 |                             fDeferComment = nullptr; | 
 | 1724 |                         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1725 |                     } | 
 | 1726 |                     break; | 
 | 1727 |                 case KeyWord::kEnum: { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1728 |                     fInEnum = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1729 |                     this->enumHeaderOut(root, child); | 
 | 1730 |                     this->enumSizeItems(child); | 
 | 1731 |                 } break; | 
 | 1732 |                 case KeyWord::kConst: | 
 | 1733 |                 case KeyWord::kConstExpr: | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1734 |                     sawConst = !memberStart || staticOnly; | 
 | 1735 |                     if (!memberStart) { | 
 | 1736 |                         memberStart = &child; | 
 | 1737 |                         staticOnly = true; | 
 | 1738 |                     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1739 |                     if (MarkType::kConst == child.fMarkType) { | 
 | 1740 |                         auto constIter = fBmhParser->fConstMap.find(child.fName); | 
 | 1741 |                         if (fBmhParser->fConstMap.end() != constIter) { | 
 | 1742 |                             const RootDefinition& bmhConst = constIter->second; | 
 | 1743 |                             this->constOut(&child, &bmhConst); | 
 | 1744 |                             fDeferComment = nullptr; | 
 | 1745 |                         } | 
 | 1746 |                     } | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1747 |                     break; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1748 |                 case KeyWord::kStatic: | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1749 |                     if (!memberStart) { | 
 | 1750 |                         memberStart = &child; | 
 | 1751 |                         staticOnly = true; | 
 | 1752 |                     } | 
 | 1753 |                     break; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1754 |                 case KeyWord::kInt: | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1755 |                 case KeyWord::kUint8_t: | 
 | 1756 |                 case KeyWord::kUint16_t: | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1757 |                 case KeyWord::kUint32_t: | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1758 |                 case KeyWord::kUint64_t: | 
| Cary Clark | 4dc5a45 | 2018-05-21 11:56:57 -0400 | [diff] [blame] | 1759 |                 case KeyWord::kUintPtr_t: | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1760 |                 case KeyWord::kUnsigned: | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1761 |                 case KeyWord::kSize_t: | 
 | 1762 |                 case KeyWord::kFloat: | 
 | 1763 |                 case KeyWord::kBool: | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1764 |                 case KeyWord::kChar: | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1765 |                 case KeyWord::kVoid: | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1766 |                     staticOnly = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1767 |                     if (!memberStart) { | 
 | 1768 |                         memberStart = &child; | 
 | 1769 |                     } | 
 | 1770 |                     break; | 
 | 1771 |                 case KeyWord::kPublic: | 
 | 1772 |                 case KeyWord::kPrivate: | 
 | 1773 |                 case KeyWord::kProtected: | 
 | 1774 |                 case KeyWord::kFriend: | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1775 |                 case KeyWord::kInline: | 
 | 1776 |                 case KeyWord::kSK_API: | 
| Cary Clark | bbfda25 | 2018-03-09 15:32:01 -0500 | [diff] [blame] | 1777 |                 case KeyWord::kTemplate: | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1778 |                     break; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1779 |                 case KeyWord::kTypedef: | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1780 |                     SkASSERT(!memberStart); | 
 | 1781 |                     memberStart = &child; | 
| Cary Clark | 27dddae | 2018-06-08 15:57:37 -0400 | [diff] [blame] | 1782 |                     deferredTypedefComment = fDeferComment; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1783 |                     sawTypedef = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1784 |                     break; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1785 |                 case KeyWord::kSK_BEGIN_REQUIRE_DENSE: | 
 | 1786 |                     requireDense = &child; | 
 | 1787 |                     break; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1788 |                 default: | 
 | 1789 |                     SkASSERT(0); | 
 | 1790 |             } | 
| Cary Clark | d98f78c | 2018-04-26 08:32:37 -0400 | [diff] [blame] | 1791 |             if (KeyWord::kUint8_t == child.fKeyWord || KeyWord::kUint32_t == child.fKeyWord) { | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1792 |                 continue; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1793 |             } else { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1794 |                 if (fInEnum && KeyWord::kClass == child.fChildren[0]->fKeyWord) { | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1795 |                     if (!this->populate(child.fChildren[0], &pair, root)) { | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1796 |                         return false; | 
 | 1797 |                     } | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1798 |                 } else { | 
 | 1799 |                     if (!this->populate(&child, &pair, root)) { | 
 | 1800 |                         return false; | 
 | 1801 |                     } | 
 | 1802 |                     if (KeyWord::kClass == child.fKeyWord || KeyWord::kStruct == child.fKeyWord) { | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1803 |                         fICSStack.pop_back(); | 
 | 1804 |                         fStructEnded = true; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1805 |                         if (fInStruct) { | 
 | 1806 |                             fInStruct = false; | 
 | 1807 |                             do { | 
 | 1808 |                                 SkASSERT(root); | 
 | 1809 |                                 root = const_cast<RootDefinition*>(root->fParent->asRoot()); | 
 | 1810 |                             } while (MarkType::kTopic == root->fMarkType || | 
 | 1811 |                                     MarkType::kSubtopic == root->fMarkType); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1812 | #if 0 | 
 | 1813 |                         } | 
 | 1814 |                         if (MarkType::kStruct == root->fMarkType || | 
 | 1815 |                                 MarkType::kClass == root->fMarkType) { | 
 | 1816 | #else | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1817 |                             SkASSERT(MarkType::kStruct == root->fMarkType || | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1818 |                                     MarkType::kClass == root->fMarkType); | 
 | 1819 | #endif | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1820 |                             fPendingMethod = false; | 
 | 1821 |                             if (startDef) { | 
 | 1822 |                                 fPendingMethod = find_start(startDef, fStart); | 
 | 1823 |                             } | 
 | 1824 |                             fOutdentNext = !fPendingMethod; | 
 | 1825 |                         } | 
 | 1826 |                     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1827 |                 } | 
 | 1828 |             } | 
 | 1829 |             continue; | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 1830 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1831 |         if (Definition::Type::kBracket == child.fType) { | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 1832 |             if (KeyWord::kEnum == child.fParent->fKeyWord || | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 1833 |                     (KeyWord::kClass == child.fParent->fKeyWord && child.fParent->fParent && | 
 | 1834 |                     KeyWord::kEnum == child.fParent->fParent->fKeyWord)) { | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 1835 |                 SkASSERT(Bracket::kBrace == child.fBracket); | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 1836 |                 this->enumMembersOut(*child.fParent); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1837 |                 this->writeString("};"); | 
 | 1838 |                 this->lf(2); | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1839 |                 startDef = child.fParent; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1840 |                 this->setStart(child.fParent->fContentEnd, child.fParent); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1841 |                 SkASSERT(';' == fStart[0]); | 
 | 1842 |                 ++fStart; | 
 | 1843 |                 fDeferComment = nullptr; | 
 | 1844 |                 fInEnum = false; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1845 |                 if (fIndentNext) { | 
 | 1846 | //                    fIndent -= 4; | 
 | 1847 |                     fIndentNext = false; | 
 | 1848 |                 } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1849 |                 continue; | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1850 |             } | 
 | 1851 |             if (fAttrDeprecated) { | 
 | 1852 |                 continue; | 
 | 1853 |             } | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 1854 |             if (KeyWord::kDefine == child.fKeyWord && this->defineOut(child)) { | 
 | 1855 |                 fDeferComment = nullptr; | 
 | 1856 |                 continue; | 
 | 1857 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1858 |             fDeferComment = nullptr; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 1859 |             if (KeyWord::kClass == def->fKeyWord || KeyWord::kStruct == def->fKeyWord) { | 
 | 1860 |                 fIndentNext = true; | 
 | 1861 |             } | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1862 |             if (!this->populate(&child, &pair, root)) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1863 |                 return false; | 
 | 1864 |             } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1865 |             if (KeyWord::kClass == def->fKeyWord || KeyWord::kStruct == def->fKeyWord) { | 
 | 1866 |                 if (def->iRootParent() && (!fStartSetter | 
 | 1867 |                         || MarkType::kMethod != fStartSetter->fMarkType)) { | 
 | 1868 |                     this->setStart(child.fContentEnd, &child); | 
 | 1869 |                     fDeferComment = nullptr; | 
 | 1870 |                 } | 
 | 1871 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1872 |             continue; | 
 | 1873 |         } | 
 | 1874 |         if (Definition::Type::kWord == child.fType) { | 
 | 1875 |             if (MarkType::kMember == child.fMarkType) { | 
| Cary Clark | 884dd7d | 2017-10-11 10:37:52 -0400 | [diff] [blame] | 1876 |                 if (!memberStart) { | 
 | 1877 |                     auto iter = def->fTokens.begin(); | 
 | 1878 |                     std::advance(iter, child.fParentIndex - 1); | 
 | 1879 |                     memberStart = &*iter; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1880 |                     staticOnly = false; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1881 |                 } | 
 | 1882 |                 if (!fStructMemberTab) { | 
 | 1883 |                     SkASSERT(KeyWord::kStruct == def->fParent->fKeyWord); | 
 | 1884 |                     fIndent += 4; | 
 | 1885 |                     this->structSizeMembers(*def->fParent); | 
 | 1886 |                     fIndent -= 4; | 
 | 1887 |                     fIndentNext = true; | 
| Cary Clark | 884dd7d | 2017-10-11 10:37:52 -0400 | [diff] [blame] | 1888 |                 } | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1889 |                 SkASSERT(fBmhStructDef); | 
 | 1890 |                 if (!fBmhStructDef->fDeprecated) { | 
 | 1891 |                     memberEnd = this->structMemberOut(memberStart, child); | 
 | 1892 |                     startDef = &child; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1893 |                     this->setStart(child.fContentEnd + 1, &child); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1894 |                     fDeferComment = nullptr; | 
 | 1895 |                 } | 
| Cary Clark | 5635631 | 2018-02-08 14:45:18 -0500 | [diff] [blame] | 1896 |             } else if (MarkType::kNone == child.fMarkType && sawConst | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1897 |                     && fEnumDef && !fEnumDef->fDeprecated) { | 
 | 1898 |                 const Definition* bmhConst = nullptr; | 
 | 1899 |                 string match; | 
 | 1900 |                 if (root) { | 
 | 1901 |                     match = root->fName + "::"; | 
 | 1902 |                 } | 
 | 1903 |                 match += string(child.fContentStart, child.fContentEnd - child.fContentStart); | 
 | 1904 |                 for (auto enumChild : fEnumDef->fChildren) { | 
 | 1905 |                     if (MarkType::kConst == enumChild->fMarkType && enumChild->fName == match) { | 
 | 1906 |                         bmhConst = enumChild; | 
 | 1907 |                         break; | 
 | 1908 |                     } | 
 | 1909 |                 } | 
 | 1910 |                 if (bmhConst) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1911 |                     this->constOut(memberStart, bmhConst); | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1912 |                     fDeferComment = nullptr; | 
 | 1913 |                     sawConst = false; | 
 | 1914 |                 } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1915 |             } else if (MarkType::kNone == child.fMarkType && sawConst && !fEnumDef) { | 
 | 1916 |                 string match; | 
 | 1917 |                 if (root) { | 
 | 1918 |                     match = root->fName + "::"; | 
 | 1919 |                     match += string(child.fContentStart, child.fContentEnd - child.fContentStart); | 
 | 1920 |                     auto bmhClassIter = fBmhParser->fClassMap.find(root->fName); | 
 | 1921 |                     if (fBmhParser->fClassMap.end() != bmhClassIter) { | 
 | 1922 |                         RootDefinition& bmhClass = bmhClassIter->second; | 
 | 1923 |                         auto constIter = std::find_if(bmhClass.fLeaves.begin(), bmhClass.fLeaves.end(), | 
 | 1924 |                                 [match](std::pair<const string, Definition>& leaf){ return match == leaf.second.fName; } ); | 
 | 1925 |                         if (bmhClass.fLeaves.end() != constIter) { | 
 | 1926 |                             const Definition& bmhConst = constIter->second; | 
 | 1927 |                             if (MarkType::kConst == bmhConst.fMarkType | 
 | 1928 |                                     && MarkType::kSubtopic == bmhConst.fParent->fMarkType) { | 
 | 1929 |                                 fBmhConst = &bmhConst; | 
 | 1930 |                                 fConstDef = &child; | 
 | 1931 |                             } | 
 | 1932 |                         } | 
 | 1933 |                     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1934 |                 } | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1935 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1936 |             if (child.fMemberStart) { | 
 | 1937 |                 memberStart = &child; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 1938 |                 staticOnly = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1939 |             } | 
| Cary Clark | 89b1456 | 2018-03-19 09:04:10 -0400 | [diff] [blame] | 1940 |             if (kAttrDeprecatedLen == (size_t) (child.fContentEnd - child.fContentStart) && | 
 | 1941 |                     !strncmp(gAttrDeprecated, child.fStart, kAttrDeprecatedLen)) { | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 1942 |                 fAttrDeprecated = &child; | 
 | 1943 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 1944 |             continue; | 
 | 1945 |         } | 
 | 1946 |         if (Definition::Type::kPunctuation == child.fType) { | 
 | 1947 |             if (Punctuation::kSemicolon == child.fPunctuation) { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1948 |                 if (sawConst && fBmhConst) {  // find bmh documentation. Parent must be subtopic. | 
 | 1949 |                     const Definition* subtopic = fBmhConst->fParent; | 
 | 1950 |                     SkASSERT(subtopic); | 
 | 1951 |                     SkASSERT(MarkType::kSubtopic == subtopic->fMarkType); | 
 | 1952 |                     auto firstConst = std::find_if(subtopic->fChildren.begin(), | 
 | 1953 |                             subtopic->fChildren.end(), | 
 | 1954 |                             [](const Definition* def){ return MarkType::kConst == def->fMarkType;}); | 
 | 1955 |                     SkASSERT(firstConst != subtopic->fChildren.end()); | 
 | 1956 |                     bool constIsFirst = *firstConst == fBmhConst; | 
 | 1957 |                     if (constIsFirst) {  // If first #Const child, output subtopic description. | 
 | 1958 |                         this->constOut(memberStart, subtopic); | 
 | 1959 |                         // find member / value / comment tabs | 
 | 1960 |                         // look for a one-to-one correspondence between bmh and include | 
 | 1961 |                         this->constSizeMembers(root); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1962 |                         fDeferComment = nullptr; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1963 |                     } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1964 |                     // after const code, output #Line description as short comment | 
 | 1965 |                     auto lineIter = std::find_if(fBmhConst->fChildren.begin(), | 
 | 1966 |                             fBmhConst->fChildren.end(), | 
 | 1967 |                             [](const Definition* def){ return MarkType::kLine == def->fMarkType; }); | 
 | 1968 |                     SkASSERT(fBmhConst->fChildren.end() != lineIter); | 
 | 1969 |                     const Definition* lineDef = *lineIter; | 
 | 1970 |                     if (fConstLength > 100) { | 
 | 1971 |                         this->writeCommentHeader(); | 
 | 1972 |                         this->writeSpace(); | 
 | 1973 |                         this->rewriteBlock(lineDef->length(), lineDef->fContentStart, Phrase::kYes); | 
 | 1974 |                         this->writeCommentTrailer(OneLine::kYes); | 
 | 1975 |                     } | 
 | 1976 |                     this->lfcr(); | 
 | 1977 |                     TextParser constText(memberStart); | 
 | 1978 |                     const char* nameEnd = constText.trimmedBracketEnd('='); | 
 | 1979 |                     SkAssertResult(constText.skipToEndBracket('=')); | 
 | 1980 |                     const char* valueEnd = constText.trimmedBracketEnd(';'); | 
 | 1981 |                     this->writeBlock((int) (nameEnd - memberStart->fContentStart), | 
 | 1982 |                             memberStart->fContentStart); | 
 | 1983 |                     this->indentToColumn(fConstValueTab); | 
 | 1984 |                     this->writeBlock((int) (valueEnd - constText.fChar), constText.fChar); | 
 | 1985 |                     this->writeString(";"); | 
 | 1986 |                     if (fConstLength <= 100) { | 
 | 1987 |                         this->indentToColumn(fConstCommentTab); | 
 | 1988 |                         this->writeString("//!<"); | 
 | 1989 |                         this->writeSpace(); | 
 | 1990 |                         this->rewriteBlock(lineDef->length(), lineDef->fContentStart, Phrase::kYes); | 
 | 1991 |                     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1992 |                     this->setStart(child.fContentStart + 1, &child); | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 1993 |                     fDeferComment = nullptr; | 
 | 1994 |                     fBmhConst = nullptr; | 
 | 1995 |                     sawConst = false; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 1996 |                 } else if (sawTypedef) { | 
 | 1997 |                     const Definition* bmhTypedef = nullptr; | 
 | 1998 |                     if (root) { | 
 | 1999 |                         SkDEBUGCODE(auto classIter = fBmhParser->fClassMap.find(root->fName)); | 
 | 2000 |                         SkASSERT(fBmhParser->fClassMap.end() != classIter); | 
 | 2001 |                         RootDefinition& classDef = fBmhParser->fClassMap[root->fName]; | 
 | 2002 |                         auto leafIter = classDef.fLeaves.find(memberStart->fName); | 
 | 2003 |                         if (classDef.fLeaves.end() != leafIter) { | 
 | 2004 |                             bmhTypedef = &leafIter->second; | 
 | 2005 |                         } | 
 | 2006 |                     } | 
 | 2007 |                     if (!bmhTypedef) { | 
 | 2008 |                         auto typedefIter = fBmhParser->fTypedefMap.find(memberStart->fName); | 
 | 2009 |                         SkASSERT(fBmhParser->fTypedefMap.end() != typedefIter); | 
 | 2010 |                         bmhTypedef = &typedefIter->second; | 
 | 2011 |                     } | 
| Cary Clark | 27dddae | 2018-06-08 15:57:37 -0400 | [diff] [blame] | 2012 |                     fDeferComment = deferredTypedefComment; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2013 |                     this->constOut(memberStart, bmhTypedef); | 
 | 2014 |                     fDeferComment = nullptr; | 
 | 2015 |                     sawTypedef = false; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2016 |                 } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2017 |                 memberStart = nullptr; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2018 |                 staticOnly = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2019 |                 if (inStruct) { | 
 | 2020 |                     fInStruct = false; | 
 | 2021 |                 } | 
 | 2022 |                 continue; | 
 | 2023 |             } | 
 | 2024 |             if (Punctuation::kLeftBrace == child.fPunctuation || | 
 | 2025 |                     Punctuation::kColon == child.fPunctuation || | 
 | 2026 |                     Punctuation::kAsterisk == child.fPunctuation | 
 | 2027 |                 ) { | 
 | 2028 |                 continue; | 
 | 2029 |             } | 
 | 2030 |         } | 
 | 2031 |     } | 
 | 2032 |     return true; | 
 | 2033 | } | 
 | 2034 |  | 
 | 2035 | bool IncludeWriter::populate(BmhParser& bmhParser) { | 
 | 2036 |     bool allPassed = true; | 
 | 2037 |     for (auto& includeMapper : fIncludeMap) { | 
 | 2038 |         size_t lastSlash = includeMapper.first.rfind('/'); | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 2039 |         if (string::npos == lastSlash) { | 
 | 2040 |             lastSlash = includeMapper.first.rfind('\\'); | 
 | 2041 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2042 |         if (string::npos == lastSlash || lastSlash >= includeMapper.first.length() - 1) { | 
 | 2043 |             return this->reportError<bool>("malformed include name"); | 
 | 2044 |         } | 
 | 2045 |         string fileName = includeMapper.first.substr(lastSlash + 1); | 
 | 2046 |         if (".h" != fileName.substr(fileName.length() - 2)) { | 
 | 2047 |             return this->reportError<bool>("expected fileName.h"); | 
 | 2048 |         } | 
 | 2049 |         string skClassName = fileName.substr(0, fileName.length() - 2); | 
 | 2050 |         fOut = fopen(fileName.c_str(), "wb"); | 
 | 2051 |         if (!fOut) { | 
 | 2052 |             SkDebugf("could not open output file %s\n", fileName.c_str()); | 
 | 2053 |             return false; | 
 | 2054 |         } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2055 |         RootDefinition* root = | 
 | 2056 |                 bmhParser.fClassMap.end() == bmhParser.fClassMap.find(skClassName) ? | 
 | 2057 |                 nullptr : &bmhParser.fClassMap[skClassName]; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2058 |         fBmhParser = &bmhParser; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2059 |         if (root) { | 
 | 2060 |             fRootTopic = root->fParent; | 
 | 2061 |             root->clearVisited(); | 
 | 2062 |         } else { | 
 | 2063 |             SkASSERT("Sk" == skClassName.substr(0, 2)); | 
 | 2064 |             string topicName = skClassName.substr(2); | 
 | 2065 |             auto topicIter = bmhParser.fTopicMap.find(topicName); | 
 | 2066 |             SkASSERT(bmhParser.fTopicMap.end() != topicIter); | 
 | 2067 |             fRootTopic = topicIter->second->asRoot(); | 
 | 2068 |             fFirstWrite = true;   // write file information after includes | 
 | 2069 |         } | 
| Cary Clark | 2d4bf5f | 2018-04-16 08:37:38 -0400 | [diff] [blame] | 2070 |         fFileName = includeMapper.second.fFileName; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2071 |         this->setStartBack(includeMapper.second.fContentStart, &includeMapper.second); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2072 |         fEnd = includeMapper.second.fContentEnd; | 
| Cary Clark | 2f46624 | 2017-12-11 16:03:17 -0500 | [diff] [blame] | 2073 |         fAnonymousEnumCount = 1; | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 2074 |         this->writeHeader(includeMapper); | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 2075 |         allPassed &= this->populate(&includeMapper.second, nullptr, root); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2076 |         this->writeBlock((int) (fEnd - fStart), fStart); | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2077 | #if 0 | 
 | 2078 |         if (fIndentStack.size() > 0) { | 
 | 2079 |             this->indentOut(); | 
 | 2080 |         } | 
 | 2081 |         SkASSERT(!fIndent); | 
 | 2082 | #else | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2083 |         fIndent = 0; | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2084 | #endif | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2085 |         this->lfcr(); | 
 | 2086 |         this->writePending(); | 
 | 2087 |         fclose(fOut); | 
| Cary Clark | 7cfcbca | 2018-01-04 16:11:51 -0500 | [diff] [blame] | 2088 |         fflush(fOut); | 
 | 2089 |         size_t slash = fFileName.find_last_of('/'); | 
 | 2090 |         if (string::npos == slash) { | 
 | 2091 |             slash = 0; | 
 | 2092 |         } | 
 | 2093 |         size_t back = fFileName.find_last_of('\\'); | 
 | 2094 |         if (string::npos == back) { | 
 | 2095 |             back = 0; | 
 | 2096 |         } | 
 | 2097 |         string dir = fFileName.substr(0, SkTMax(slash, back) + 1); | 
 | 2098 |         string readname = dir + fileName; | 
 | 2099 |         if (this->writtenFileDiffers(fileName, readname)) { | 
 | 2100 |             SkDebugf("wrote updated %s\n", fileName.c_str()); | 
 | 2101 |         } else { | 
 | 2102 |             remove(fileName.c_str()); | 
 | 2103 |         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2104 |     } | 
 | 2105 |     return allPassed; | 
 | 2106 | } | 
 | 2107 |  | 
 | 2108 | // change Xxx_Xxx to xxx xxx | 
 | 2109 | static string ConvertRef(const string str, bool first) { | 
 | 2110 |     string substitute; | 
 | 2111 |     for (char c : str) { | 
 | 2112 |         if ('_' == c) { | 
 | 2113 |             c = ' ';  // change Xxx_Xxx to xxx xxx | 
 | 2114 |         } else if (isupper(c) && !first) { | 
 | 2115 |             c = tolower(c); | 
 | 2116 |         } | 
 | 2117 |         substitute += c; | 
 | 2118 |         first = false; | 
 | 2119 |     } | 
 | 2120 |     return substitute; | 
 | 2121 | } | 
 | 2122 |  | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2123 | string IncludeWriter::resolveMethod(const char* start, const char* end, bool first) { | 
 | 2124 |     string methodname(start, end - start); | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2125 |     if (string::npos != methodname.find("()")) { | 
 | 2126 |         return ""; | 
 | 2127 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2128 |     string substitute; | 
 | 2129 |     auto rootDefIter = fBmhParser->fMethodMap.find(methodname); | 
 | 2130 |     if (fBmhParser->fMethodMap.end() != rootDefIter) { | 
 | 2131 |         substitute = methodname + "()"; | 
 | 2132 |     } else { | 
| Cary Clark | 1eace2d | 2017-07-31 07:52:43 -0400 | [diff] [blame] | 2133 |         RootDefinition* parent = nullptr; | 
 | 2134 |         for (auto candidate : fRootTopic->fChildren) { | 
 | 2135 |             if (MarkType::kClass == candidate->fMarkType | 
 | 2136 |                     || MarkType::kStruct == candidate->fMarkType) { | 
 | 2137 |                 parent = candidate->asRoot(); | 
 | 2138 |                 break; | 
 | 2139 |             } | 
 | 2140 |         } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2141 |         if (parent) { | 
 | 2142 |             auto defRef = parent->find(parent->fName + "::" + methodname, | 
 | 2143 |                     RootDefinition::AllowParens::kNo); | 
 | 2144 |             if (defRef && MarkType::kMethod == defRef->fMarkType) { | 
 | 2145 |                 substitute = methodname + "()"; | 
 | 2146 |             } else { | 
 | 2147 |                 auto defineIter = fBmhParser->fDefineMap.find(methodname); | 
 | 2148 |                 if (fBmhParser->fDefineMap.end() != defineIter) { | 
 | 2149 |                     const RootDefinition& defineDef = defineIter->second; | 
 | 2150 |                     auto codeIter = std::find_if(defineDef.fChildren.begin(), | 
 | 2151 |                             defineDef.fChildren.end(), | 
 | 2152 |                             [](Definition* child){ return MarkType::kCode == child->fMarkType; } ); | 
 | 2153 |                     if (defineDef.fChildren.end() != codeIter) { | 
 | 2154 |                         const Definition* codeDef = *codeIter; | 
 | 2155 |                         string codeContents(codeDef->fContentStart, codeDef->length()); | 
 | 2156 |                         size_t namePos = codeContents.find(methodname); | 
 | 2157 |                         if (string::npos != namePos) { | 
 | 2158 |                             size_t parenPos = namePos + methodname.length(); | 
 | 2159 |                             if (parenPos < codeContents.length() && '(' == codeContents[parenPos]) { | 
 | 2160 |                                 substitute = methodname + "()"; | 
 | 2161 |                             } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2162 |                         } | 
 | 2163 |                     } | 
 | 2164 |                 } | 
 | 2165 |             } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2166 |         } | 
 | 2167 |     } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2168 |     if (fMethodDef && methodname == fMethodDef->fName) { | 
 | 2169 |         TextParser report(fBmhMethod); | 
 | 2170 |         report.reportError("method should not include references to itself"); | 
 | 2171 |         return ""; | 
 | 2172 |     } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2173 |     if (fBmhMethod) { | 
 | 2174 |         for (auto child : fBmhMethod->fChildren) { | 
 | 2175 |             if (MarkType::kParam != child->fMarkType) { | 
 | 2176 |                 continue; | 
 | 2177 |             } | 
 | 2178 |             if (methodname == child->fName) { | 
 | 2179 |                 return ""; | 
 | 2180 |             } | 
 | 2181 |         } | 
 | 2182 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2183 |     return substitute; | 
 | 2184 | } | 
 | 2185 |  | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2186 | string IncludeWriter::resolveAlias(const Definition* def) { | 
 | 2187 |     for (auto child : def->fChildren) { | 
 | 2188 |         if (MarkType::kSubstitute == child->fMarkType) { | 
 | 2189 |             return string(child->fContentStart, (int) (child->fContentEnd - child->fContentStart)); | 
 | 2190 |         } | 
 | 2191 |         if (MarkType::kAlias == child->fMarkType && def->fName == child->fName) { | 
 | 2192 |             return this->resolveAlias(child); | 
 | 2193 |         } | 
 | 2194 |     } | 
 | 2195 |     return ""; | 
 | 2196 | } | 
 | 2197 |  | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 2198 | string IncludeWriter::resolveRef(const char* start, const char* end, bool first, | 
 | 2199 |         RefType* refType) { | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 2200 |         // look up Xxx_Xxx | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2201 |     string undername(start, end - start); | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 2202 |     for (const auto& external : fBmhParser->fExternals) { | 
 | 2203 |         if (external.fName == undername) { | 
 | 2204 |             *refType = RefType::kExternal; | 
 | 2205 |             return external.fName; | 
 | 2206 |         } | 
 | 2207 |     } | 
 | 2208 |     *refType = RefType::kNormal; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2209 |     SkASSERT(string::npos == undername.find(' ')); | 
 | 2210 |     const Definition* rootDef = nullptr; | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2211 |     string substitute; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2212 |     { | 
 | 2213 |         auto rootDefIter = fBmhParser->fTopicMap.find(undername); | 
 | 2214 |         if (fBmhParser->fTopicMap.end() != rootDefIter) { | 
 | 2215 |             rootDef = rootDefIter->second; | 
 | 2216 |         } else { | 
 | 2217 |             string prefixedName = fRootTopic->fName + '_' + undername; | 
 | 2218 |             rootDefIter = fBmhParser->fTopicMap.find(prefixedName); | 
 | 2219 |             if (fBmhParser->fTopicMap.end() != rootDefIter) { | 
 | 2220 |                 rootDef = rootDefIter->second; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 2221 |             } else if (fBmhStructDef) { | 
 | 2222 |                 string localPrefix = fBmhStructDef->fFiddle + '_' + undername; | 
| Cary Clark | bad5ad7 | 2017-08-03 17:14:08 -0400 | [diff] [blame] | 2223 |                 rootDefIter = fBmhParser->fTopicMap.find(localPrefix); | 
 | 2224 |                 if (fBmhParser->fTopicMap.end() != rootDefIter) { | 
 | 2225 |                     rootDef = rootDefIter->second; | 
 | 2226 |                 } | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2227 |                 if (!rootDef) { | 
 | 2228 |                     size_t doubleColon = fBmhStructDef->fName.rfind("::"); | 
 | 2229 |                     if (string::npos != doubleColon && undername | 
 | 2230 |                             == fBmhStructDef->fName.substr(doubleColon + 2)) { | 
 | 2231 |                         substitute = fBmhStructDef->fName; | 
 | 2232 |                     } | 
 | 2233 |                 } | 
 | 2234 |             } | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2235 |             if (!rootDef && fEnumDef && "Sk" + prefixedName == fEnumDef->fFiddle) { | 
 | 2236 |                 rootDef = fEnumDef; | 
 | 2237 |             } | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2238 |             if (!rootDef && !substitute.length()) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2239 |                 auto aliasIter = fBmhParser->fAliasMap.find(undername); | 
 | 2240 |                 if (fBmhParser->fAliasMap.end() != aliasIter) { | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2241 |                     rootDef = aliasIter->second; | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 2242 |                 } else if (fInEnum && fEnumDef && this->findEnumSubtopic(undername, &rootDef)) { | 
 | 2243 |                     ; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2244 |                 } else if (!first) { | 
| Cary Clark | 186d08f | 2018-04-03 08:43:27 -0400 | [diff] [blame] | 2245 |                     this->fChar = start; | 
| Cary Clark | ffb3d68 | 2018-05-17 12:17:28 -0400 | [diff] [blame] | 2246 |                     this->fLine = start; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2247 |                     this->reportError("reference unfound"); | 
 | 2248 |                     return ""; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2249 |                 } | 
 | 2250 |             } | 
 | 2251 |         } | 
 | 2252 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2253 |     if (rootDef) { | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2254 |         MarkType rootType = rootDef->fMarkType; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2255 |         if (MarkType::kSubtopic == rootType || MarkType::kTopic == rootType | 
 | 2256 |                 || MarkType::kAlias == rootType) { | 
 | 2257 |             substitute = this->resolveAlias(rootDef); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2258 |         } | 
 | 2259 |         if (!substitute.length()) { | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2260 |             string match = rootDef->fName; | 
 | 2261 |             size_t index; | 
 | 2262 |             while (string::npos != (index = match.find('_'))) { | 
 | 2263 |                 match.erase(index, 1); | 
 | 2264 |             } | 
 | 2265 |             string skmatch = "Sk" + match; | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2266 |             auto parent = MarkType::kAlias == rootType ? rootDef->fParent : rootDef; | 
| Cary Clark | 78c110e | 2018-02-09 16:49:09 -0500 | [diff] [blame] | 2267 |             for (auto child : parent->fChildren) { | 
 | 2268 |                 // there may be more than one | 
 | 2269 |                 // prefer the one mostly closely matching in text | 
 | 2270 |                 if ((MarkType::kClass == child->fMarkType || | 
 | 2271 |                     MarkType::kStruct == child->fMarkType || | 
 | 2272 |                     (MarkType::kEnum == child->fMarkType && !child->fAnonymous) || | 
 | 2273 |                     MarkType::kEnumClass == child->fMarkType) && (match == child->fName || | 
 | 2274 |                     skmatch == child->fName)) { | 
 | 2275 |                     substitute = child->fName; | 
 | 2276 |                     break; | 
 | 2277 |                 } | 
 | 2278 |             } | 
 | 2279 |         } | 
 | 2280 |         if (!substitute.length()) { | 
 | 2281 |             for (auto child : rootDef->fChildren) { | 
 | 2282 |                 // there may be more than one | 
 | 2283 |                 // if so, it's a bug since it's unknown which is the right one | 
 | 2284 |                 if (MarkType::kClass == child->fMarkType || | 
 | 2285 |                         MarkType::kStruct == child->fMarkType || | 
 | 2286 |                         (MarkType::kEnum == child->fMarkType && !child->fAnonymous) || | 
 | 2287 |                         MarkType::kEnumClass == child->fMarkType) { | 
 | 2288 |                     SkASSERT("" == substitute); | 
 | 2289 |                     substitute = child->fName; | 
 | 2290 |                     if (MarkType::kEnum == child->fMarkType) { | 
 | 2291 |                         size_t parentClassEnd = substitute.find("::"); | 
 | 2292 |                         SkASSERT(string::npos != parentClassEnd); | 
 | 2293 |                         string subEnd = substitute.substr(parentClassEnd + 2); | 
 | 2294 |                         if (fInEnum) { | 
 | 2295 |                             substitute = subEnd; | 
 | 2296 |                         } | 
 | 2297 |                         if (subEnd == undername) { | 
 | 2298 |                             break; | 
 | 2299 |                         } | 
 | 2300 |                     } | 
 | 2301 |                 } | 
 | 2302 |             } | 
 | 2303 |         } | 
 | 2304 |         if (!substitute.length()) { | 
 | 2305 |             const Definition* parent = rootDef; | 
 | 2306 |             do { | 
 | 2307 |                 parent = parent->fParent; | 
 | 2308 |             } while (parent && (MarkType::kSubtopic == parent->fMarkType | 
 | 2309 |                         || MarkType::kTopic == parent->fMarkType)); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2310 |             if (parent) { | 
 | 2311 |                 if (MarkType::kClass == parent->fMarkType || | 
 | 2312 |                         MarkType::kStruct == parent->fMarkType || | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 2313 |                         (MarkType::kEnum == parent->fMarkType && !parent->fAnonymous) || | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2314 |                         MarkType::kEnumClass == parent->fMarkType) { | 
 | 2315 |                     if (parent->fParent != fRootTopic) { | 
 | 2316 |                         substitute = parent->fName; | 
| Cary Clark | 2a8c48b | 2018-02-15 17:31:24 -0500 | [diff] [blame] | 2317 |                         substitute += ' '; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2318 |                         substitute += ConvertRef(rootDef->fName, false); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2319 |                     } else { | 
| Cary Clark | 137b874 | 2018-05-30 09:21:49 -0400 | [diff] [blame] | 2320 |                         size_t underpos = undername.find('_'); | 
 | 2321 |                         if (string::npos != underpos) { | 
 | 2322 |                             string parentName = undername.substr(0, underpos); | 
 | 2323 |                             string skName = "Sk" + parentName; | 
 | 2324 |                             if (skName == parent->fName) { | 
 | 2325 |                                 SkASSERT(start >= fLastDescription->fContentStart); | 
 | 2326 |                                 string lastDescription = string(fLastDescription->fContentStart, | 
 | 2327 |                                         (int) (start - fLastDescription->fContentStart)); | 
 | 2328 |                                 size_t lineStart = lastDescription.rfind('\n'); | 
 | 2329 |                                 SkASSERT(string::npos != lineStart); | 
 | 2330 |                                 fLine = fLastDescription->fContentStart + lineStart + 1; | 
 | 2331 |                                 fChar = start; | 
 | 2332 |                                 fEnd = end; | 
 | 2333 |                                 return this->reportError<string>("remove underline"); | 
 | 2334 |                             } | 
 | 2335 |                         } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2336 |                         substitute += ConvertRef(undername, first); | 
 | 2337 |                     } | 
 | 2338 |                 } | 
 | 2339 |             } | 
 | 2340 |         } | 
 | 2341 |     } | 
| Cary Clark | 1eace2d | 2017-07-31 07:52:43 -0400 | [diff] [blame] | 2342 |     // Ensure first word after period is capitalized if substitute is lower cased. | 
 | 2343 |     if (first && isupper(start[0]) && substitute.length() > 0 && islower(substitute[0])) { | 
 | 2344 |         substitute[0] = start[0]; | 
 | 2345 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2346 |     return substitute; | 
 | 2347 | } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2348 |  | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2349 | int IncludeWriter::lookupMethod(const PunctuationState punctuation, const Word word, | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2350 |         const int lastSpace, const int run, int lastWrite, const char* data, | 
 | 2351 |         bool hasIndirection) { | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2352 |     int wordStart = lastSpace; | 
 | 2353 |     while (' ' >= data[wordStart]) { | 
 | 2354 |         ++wordStart; | 
 | 2355 |     } | 
 | 2356 |     const int wordEnd = PunctuationState::kDelimiter == punctuation || | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2357 |             PunctuationState::kParen == punctuation || | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2358 |             PunctuationState::kPeriod == punctuation ? run - 1 : run; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2359 |     string temp; | 
 | 2360 |     if (hasIndirection && '(' != data[wordEnd - 1] && ')' != data[wordEnd - 1]) { | 
 | 2361 |         // FIXME: hard-coded to assume a.b or a->b is a.b() or a->b(). | 
 | 2362 |         // need to check class a for member b to see if this is so | 
 | 2363 |         TextParser parser(fFileName, &data[wordStart], &data[wordEnd], fLineCount); | 
 | 2364 |         const char* indirection = parser.anyOf(".>"); | 
 | 2365 |         if (&data[wordEnd] <= &indirection[2] || 'f' != indirection[1] || | 
 | 2366 |                 !isupper(indirection[2])) { | 
 | 2367 |             temp = string(&data[wordStart], wordEnd - wordStart) + "()"; | 
 | 2368 |         } | 
 | 2369 |     } else { | 
 | 2370 |         temp = this->resolveMethod(&data[wordStart], &data[wordEnd], Word::kFirst == word); | 
 | 2371 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2372 |     if (temp.length()) { | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2373 |         if (wordStart > lastWrite) { | 
 | 2374 |             SkASSERT(data[wordStart - 1] >= ' '); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2375 |             if (' ' == data[lastWrite]) { | 
 | 2376 |                 this->writeSpace(); | 
 | 2377 |             } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2378 |             this->firstBlockTrim(wordStart - lastWrite, &data[lastWrite]); | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2379 |             if (' ' == data[wordStart - 1]) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2380 |                 this->writeSpace(); | 
 | 2381 |             } | 
 | 2382 |         } | 
 | 2383 |         SkASSERT(temp[temp.length() - 1] > ' '); | 
 | 2384 |         this->writeString(temp.c_str()); | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2385 |         lastWrite = wordEnd; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2386 |     } | 
 | 2387 |     return lastWrite; | 
 | 2388 | } | 
 | 2389 |  | 
 | 2390 | int IncludeWriter::lookupReference(const PunctuationState punctuation, const Word word, | 
 | 2391 |         const int start, const int run, int lastWrite, const char last, const char* data) { | 
 | 2392 |     const int end = PunctuationState::kDelimiter == punctuation || | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2393 |             PunctuationState::kParen == punctuation || | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2394 |             PunctuationState::kPeriod == punctuation ? run - 1 : run; | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 2395 |     RefType refType = RefType::kUndefined; | 
 | 2396 |     string resolved = string(&data[start], (size_t) (end - start)); | 
 | 2397 |     string temp = this->resolveRef(&data[start], &data[end], Word::kFirst == word, &refType); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2398 |     if (!temp.length()) { | 
 | 2399 |         if (Word::kFirst != word && '_' != last) { | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 2400 |             temp = ConvertRef(resolved, false); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2401 |         } | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 2402 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2403 |     if (temp.length()) { | 
 | 2404 |         if (start > lastWrite) { | 
 | 2405 |             SkASSERT(data[start - 1] >= ' '); | 
 | 2406 |             if (' ' == data[lastWrite]) { | 
 | 2407 |                 this->writeSpace(); | 
 | 2408 |             } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2409 |             this->firstBlockTrim(start - lastWrite, &data[lastWrite]); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2410 |             if (' ' == data[start - 1]) { | 
 | 2411 |                 this->writeSpace(); | 
 | 2412 |             } | 
 | 2413 |         } | 
 | 2414 |         SkASSERT(temp[temp.length() - 1] > ' '); | 
 | 2415 |         this->writeString(temp.c_str()); | 
 | 2416 |         lastWrite = end; | 
 | 2417 |     } | 
 | 2418 |     return lastWrite; | 
 | 2419 | } | 
 | 2420 |  | 
 | 2421 | /* returns true if rewriteBlock wrote linefeeds */ | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 2422 | IncludeWriter::Wrote IncludeWriter::rewriteBlock(int size, const char* data, Phrase phrase) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2423 |     bool wroteLineFeeds = false; | 
 | 2424 |     while (size > 0 && data[0] <= ' ') { | 
 | 2425 |         --size; | 
 | 2426 |         ++data; | 
 | 2427 |     } | 
 | 2428 |     while (size > 0 && data[size - 1] <= ' ') { | 
 | 2429 |         --size; | 
 | 2430 |     } | 
 | 2431 |     if (0 == size) { | 
 | 2432 |         return Wrote::kNone; | 
 | 2433 |     } | 
| Cary Clark | 0d22539 | 2018-06-07 09:59:07 -0400 | [diff] [blame] | 2434 |     if (fReturnOnWrite) { | 
 | 2435 |         return Wrote::kChars; | 
 | 2436 |     } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2437 |     int run = 0; | 
 | 2438 |     Word word = Word::kStart; | 
| Cary Clark | d0530ba | 2017-09-14 11:25:39 -0400 | [diff] [blame] | 2439 |     PunctuationState punctuation = Phrase::kNo == phrase ? | 
 | 2440 |             PunctuationState::kStart : PunctuationState::kSpace; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2441 |     int start = 0; | 
 | 2442 |     int lastWrite = 0; | 
 | 2443 |     int lineFeeds = 0; | 
 | 2444 |     int lastPrintable = 0; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2445 |     int lastSpace = -1; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2446 |     char c = 0; | 
| Kevin Lubick | 4284613 | 2018-01-05 10:11:11 -0500 | [diff] [blame] | 2447 |     char last = 0; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2448 |     bool embeddedIndirection = false; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2449 |     bool embeddedSymbol = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2450 |     bool hasLower = false; | 
 | 2451 |     bool hasUpper = false; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2452 |     bool hasIndirection = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2453 |     bool hasSymbol = false; | 
 | 2454 |     while (run < size) { | 
 | 2455 |         last = c; | 
 | 2456 |         c = data[run]; | 
 | 2457 |         SkASSERT(' ' <= c || '\n' == c); | 
 | 2458 |         if (lineFeeds && ' ' < c) { | 
 | 2459 |             if (lastPrintable >= lastWrite) { | 
 | 2460 |                 if (' ' == data[lastWrite]) { | 
 | 2461 |                     this->writeSpace(); | 
| Cary Clark | a560c47 | 2017-11-27 10:44:06 -0500 | [diff] [blame] | 2462 |                     lastWrite++; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2463 |                 } | 
 | 2464 |                 this->writeBlock(lastPrintable - lastWrite + 1, &data[lastWrite]); | 
 | 2465 |             } | 
 | 2466 |             if (lineFeeds > 1) { | 
 | 2467 |                 this->lf(2); | 
 | 2468 |             } | 
 | 2469 |             this->lfcr(); // defer the indent until non-whitespace is seen | 
 | 2470 |             lastWrite = run; | 
 | 2471 |             lineFeeds = 0; | 
 | 2472 |         } | 
 | 2473 |         if (' ' < c) { | 
 | 2474 |             lastPrintable = run; | 
 | 2475 |         } | 
 | 2476 |         switch (c) { | 
 | 2477 |             case '\n': | 
 | 2478 |                 ++lineFeeds; | 
 | 2479 |                 wroteLineFeeds = true; | 
 | 2480 |             case ' ': | 
 | 2481 |                 switch (word) { | 
 | 2482 |                     case Word::kStart: | 
 | 2483 |                         break; | 
 | 2484 |                     case Word::kUnderline: | 
 | 2485 |                     case Word::kCap: | 
 | 2486 |                     case Word::kFirst: | 
 | 2487 |                         if (!hasLower) { | 
 | 2488 |                             break; | 
 | 2489 |                         } | 
 | 2490 |                         lastWrite = this->lookupReference(punctuation, word, start, run, | 
 | 2491 |                                 lastWrite, last, data); | 
 | 2492 |                         break; | 
 | 2493 |                     case Word::kMixed: | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2494 |                         if (hasUpper && hasLower && !hasSymbol && lastSpace > 0) { | 
 | 2495 |                             lastWrite = this->lookupMethod(punctuation, word, lastSpace, run, | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2496 |                                     lastWrite, data, hasIndirection); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2497 |                         } | 
 | 2498 |                         break; | 
 | 2499 |                     default: | 
 | 2500 |                         SkASSERT(0); | 
 | 2501 |                 } | 
| Cary Clark | 1eace2d | 2017-07-31 07:52:43 -0400 | [diff] [blame] | 2502 |                 punctuation = PunctuationState::kPeriod == punctuation || | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 2503 |                         (PunctuationState::kStart == punctuation && ' ' >= last) ? | 
| Cary Clark | 1eace2d | 2017-07-31 07:52:43 -0400 | [diff] [blame] | 2504 |                         PunctuationState::kStart : PunctuationState::kSpace; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2505 |                 word = Word::kStart; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2506 |                 embeddedIndirection = false; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2507 |                 embeddedSymbol = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2508 |                 hasLower = false; | 
 | 2509 |                 hasUpper = false; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2510 |                 hasIndirection = false; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2511 |                 hasSymbol = false; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2512 |                 lastSpace = run; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2513 |                 break; | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2514 |             case '.': case ',': case ';': case ':': case ')': | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2515 |                 switch (word) { | 
 | 2516 |                     case Word::kStart: | 
 | 2517 |                         punctuation = PunctuationState::kDelimiter; | 
 | 2518 |                     case Word::kCap: | 
 | 2519 |                     case Word::kFirst: | 
 | 2520 |                     case Word::kUnderline: | 
 | 2521 |                     case Word::kMixed: | 
 | 2522 |                         if (PunctuationState::kDelimiter == punctuation || | 
 | 2523 |                                 PunctuationState::kPeriod == punctuation) { | 
 | 2524 |                             word = Word::kMixed; | 
 | 2525 |                         } | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2526 |                         punctuation = '.' == c ? PunctuationState::kPeriod : | 
 | 2527 |                                 PunctuationState::kDelimiter; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2528 |                         break; | 
 | 2529 |                     default: | 
 | 2530 |                         SkASSERT(0); | 
 | 2531 |                 } | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2532 |                 ('.' == c ? embeddedIndirection : embeddedSymbol) = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2533 |                 break; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2534 |             case '>': | 
 | 2535 |                 if ('-' == last) { | 
 | 2536 |                     embeddedIndirection = true; | 
 | 2537 |                     break; | 
 | 2538 |                 } | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2539 |             case '\'': // possessive apostrophe isn't treated as delimiting punctation | 
| Cary Clark | ce10124 | 2017-09-01 15:51:02 -0400 | [diff] [blame] | 2540 |             case '\"': // quote is passed straight through | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2541 |             case '=': | 
 | 2542 |             case '!':  // assumed not to be punctuation, but a programming symbol | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2543 |             case '&': case '<': case '{': case '}': case '/': case '*': case '[': case ']': | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2544 |                 word = Word::kMixed; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2545 |                 embeddedSymbol = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2546 |                 break; | 
 | 2547 |             case '(': | 
 | 2548 |                 if (' ' == last) { | 
| Cary Clark | c68ba1d | 2018-02-20 10:35:29 -0500 | [diff] [blame] | 2549 |                     punctuation = PunctuationState::kParen; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2550 |                 } else { | 
 | 2551 |                     word = Word::kMixed; | 
 | 2552 |                 } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2553 |                 embeddedSymbol = true; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2554 |                 break; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2555 |             case '_': | 
 | 2556 |                 switch (word) { | 
 | 2557 |                     case Word::kStart: | 
 | 2558 |                         word = Word::kMixed; | 
 | 2559 |                         break; | 
 | 2560 |                     case Word::kCap: | 
 | 2561 |                     case Word::kFirst: | 
 | 2562 |                     case Word::kUnderline: | 
 | 2563 |                         word = Word::kUnderline; | 
 | 2564 |                         break; | 
 | 2565 |                     case Word::kMixed: | 
 | 2566 |                         break; | 
 | 2567 |                     default: | 
 | 2568 |                         SkASSERT(0); | 
 | 2569 |                 } | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2570 |                 hasSymbol |= embeddedSymbol; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2571 |                 break; | 
| Cary Clark | 73fa972 | 2017-08-29 17:36:51 -0400 | [diff] [blame] | 2572 |             case '+': | 
 | 2573 |                 // hackery to allow C++ | 
 | 2574 |                 SkASSERT('C' == last || '+' == last);  // FIXME: don't allow + outside of #Formula | 
 | 2575 |                 break; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2576 |             case 'A': case 'B': case 'C': case 'D': case 'E': | 
 | 2577 |             case 'F': case 'G': case 'H': case 'I': case 'J': | 
 | 2578 |             case 'K': case 'L': case 'M': case 'N': case 'O': | 
 | 2579 |             case 'P': case 'Q': case 'R': case 'S': case 'T': | 
 | 2580 |             case 'U': case 'V': case 'W': case 'X': case 'Y': | 
 | 2581 |             case 'Z': | 
 | 2582 |                 switch (word) { | 
 | 2583 |                     case Word::kStart: | 
 | 2584 |                         word = PunctuationState::kStart == punctuation ? Word::kFirst : Word::kCap; | 
 | 2585 |                         start = run; | 
 | 2586 |                         break; | 
 | 2587 |                     case Word::kCap: | 
 | 2588 |                     case Word::kFirst: | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 2589 |                         if (!isupper(last) && '~' != last) { | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2590 |                             word = Word::kMixed; | 
 | 2591 |                         } | 
 | 2592 |                         break; | 
 | 2593 |                     case Word::kUnderline: | 
 | 2594 |                         // some word in Xxx_XXX_Xxx can be all upper, but all can't: XXX_XXX | 
 | 2595 |                         if ('_' != last && !isupper(last)) { | 
 | 2596 |                             word = Word::kMixed; | 
 | 2597 |                         } | 
 | 2598 |                         break; | 
 | 2599 |                     case Word::kMixed: | 
 | 2600 |                         break; | 
 | 2601 |                     default: | 
 | 2602 |                         SkASSERT(0); | 
 | 2603 |                 } | 
 | 2604 |                 hasUpper = true; | 
 | 2605 |                 if (PunctuationState::kPeriod == punctuation || | 
 | 2606 |                         PunctuationState::kDelimiter == punctuation) { | 
 | 2607 |                     word = Word::kMixed; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2608 |                 } | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2609 |                 hasIndirection |= embeddedIndirection; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2610 |                 hasSymbol |= embeddedSymbol; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2611 |                 break; | 
 | 2612 |             case 'a': case 'b': case 'c': case 'd': case 'e': | 
 | 2613 |             case 'f': case 'g': case 'h': case 'i': case 'j': | 
 | 2614 |             case 'k': case 'l': case 'm': case 'n': case 'o': | 
 | 2615 |             case 'p': case 'q': case 'r': case 's': case 't': | 
 | 2616 |             case 'u': case 'v': case 'w': case 'x': case 'y': | 
| Ben Wagner | 63fd760 | 2017-10-09 15:45:33 -0400 | [diff] [blame] | 2617 |             case 'z': | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2618 |             case '0': case '1': case '2': case '3': case '4': | 
 | 2619 |             case '5': case '6': case '7': case '8': case '9': | 
| Cary Clark | 682c58d | 2018-05-16 07:07:07 -0400 | [diff] [blame] | 2620 |             case '%':  // to do : ensure that preceding is a number | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2621 |             case '-': | 
 | 2622 |                 switch (word) { | 
 | 2623 |                     case Word::kStart: | 
 | 2624 |                         word = Word::kMixed; | 
 | 2625 |                         break; | 
 | 2626 |                     case Word::kMixed: | 
 | 2627 |                     case Word::kCap: | 
 | 2628 |                     case Word::kFirst: | 
 | 2629 |                     case Word::kUnderline: | 
 | 2630 |                         break; | 
 | 2631 |                     default: | 
 | 2632 |                         SkASSERT(0); | 
 | 2633 |                 } | 
 | 2634 |                 hasLower = true; | 
 | 2635 |                 punctuation = PunctuationState::kStart; | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2636 |                 hasIndirection |= embeddedIndirection; | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2637 |                 hasSymbol |= embeddedSymbol; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2638 |                 break; | 
| Cary Clark | 154beea | 2017-10-26 07:58:48 -0400 | [diff] [blame] | 2639 |             case '~': | 
 | 2640 |                 SkASSERT(Word::kStart == word); | 
 | 2641 |                 word = PunctuationState::kStart == punctuation ? Word::kFirst : Word::kCap; | 
 | 2642 |                 start = run; | 
 | 2643 |                 hasUpper = true; | 
 | 2644 |                 hasIndirection |= embeddedIndirection; | 
 | 2645 |                 hasSymbol |= embeddedSymbol; | 
 | 2646 |                 break; | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2647 |             default: | 
 | 2648 |                 SkASSERT(0); | 
 | 2649 |         } | 
 | 2650 |         ++run; | 
 | 2651 |     } | 
 | 2652 |     if ((word == Word::kCap || word == Word::kFirst || word == Word::kUnderline) && hasLower) { | 
 | 2653 |         lastWrite = this->lookupReference(punctuation, word, start, run, lastWrite, last, data); | 
| Cary Clark | 579985c | 2017-07-31 11:48:27 -0400 | [diff] [blame] | 2654 |     } else if (word == Word::kMixed && hasUpper && hasLower && !hasSymbol && lastSpace > 0) { | 
| Cary Clark | 6fc5041 | 2017-09-21 12:31:06 -0400 | [diff] [blame] | 2655 |         lastWrite = this->lookupMethod(punctuation, word, lastSpace, run, lastWrite, data, | 
 | 2656 |                 hasIndirection && !hasSymbol); | 
| Cary Clark | 8032b98 | 2017-07-28 11:04:54 -0400 | [diff] [blame] | 2657 |     } | 
 | 2658 |     if (run > lastWrite) { | 
 | 2659 |         if (' ' == data[lastWrite]) { | 
 | 2660 |             this->writeSpace(); | 
 | 2661 |         } | 
 | 2662 |         this->writeBlock(run - lastWrite, &data[lastWrite]); | 
 | 2663 |     } | 
 | 2664 |     return wroteLineFeeds ? Wrote::kLF : Wrote::kChars; | 
 | 2665 | } | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 2666 |  | 
 | 2667 | static string paddedString(int num) { | 
 | 2668 |     auto padded = std::to_string(num); | 
 | 2669 |     padded.insert(0, 2U - std::min(string::size_type(2), padded.length()), '0'); | 
 | 2670 |     return padded; | 
 | 2671 | } | 
 | 2672 |  | 
 | 2673 | bool IncludeWriter::writeHeader(std::pair<const string, Definition>& include) { | 
 | 2674 |     std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); | 
 | 2675 |     time_t tt = std::chrono::system_clock::to_time_t(now); | 
 | 2676 |     tm local_tm = *localtime(&tt); | 
 | 2677 |  | 
 | 2678 |     // find end of copyright header | 
 | 2679 |     fChar = fStart; | 
 | 2680 |     if (!this->skipExact( | 
 | 2681 |             "/*\n" | 
 | 2682 |             " * Copyright ")) { | 
 | 2683 |         return this->reportError<bool>("copyright mismatch 1"); | 
 | 2684 |     } | 
 | 2685 |     const char* date = fChar; | 
 | 2686 |     this->skipToSpace(); | 
 | 2687 |     string yearStr(date, fChar - date); | 
 | 2688 |     int year = stoi(yearStr); | 
 | 2689 |     if (year < 2005 || year > local_tm.tm_year + 1900) { | 
 | 2690 |         return this->reportError<bool>("copyright year out of range"); | 
 | 2691 |     } | 
 | 2692 |     this->skipSpace(); | 
 | 2693 |     const char android[] = "The Android Open Source Project"; | 
 | 2694 |     const char google[] = "Google Inc."; | 
 | 2695 |     if (this->startsWith(android)) { | 
 | 2696 |         this->skipExact(android); | 
 | 2697 |     } else if (!this->skipExact(google)) { | 
 | 2698 |         return this->reportError<bool>("copyright mismatch 2"); | 
 | 2699 |     } | 
 | 2700 |     if (!this->skipExact( | 
 | 2701 |             "\n" | 
 | 2702 |             " *\n" | 
 | 2703 |             " * Use of this source code is governed by a BSD-style license that can be\n" | 
 | 2704 |             " * found in the LICENSE file.\n" | 
 | 2705 |             " */\n" | 
 | 2706 |             "\n" | 
 | 2707 |             )) { | 
 | 2708 |         return this->reportError<bool>("copyright mismatch 2"); | 
 | 2709 |     } | 
 | 2710 |     this->writeBlock(fChar - fStart, fStart); | 
 | 2711 |     this->lf(2); | 
 | 2712 |     this->writeString("/* Generated by tools/bookmaker from"); | 
 | 2713 |     this->writeSpace(); | 
 | 2714 |     string includeName = include.first; | 
 | 2715 |     std::replace(includeName.begin(), includeName.end(), '\\', '/'); | 
 | 2716 |     this->writeString(includeName); | 
 | 2717 |     this->writeSpace(); | 
 | 2718 |     this->writeString("and"); | 
 | 2719 |     this->writeSpace(); | 
 | 2720 |     string bmhName = fRootTopic->fFileName; | 
 | 2721 |     std::replace(bmhName.begin(), bmhName.end(), '\\', '/'); | 
 | 2722 |     this->writeString(bmhName); | 
 | 2723 |     this->lfcr(); | 
 | 2724 |     fIndent = 3; | 
 | 2725 |     string dateTimeStr = std::to_string(local_tm.tm_year + 1900) + "-" | 
 | 2726 |             + paddedString(local_tm.tm_mon + 1) + "-" | 
 | 2727 |             + paddedString(local_tm.tm_mday) + " " | 
 | 2728 |             + paddedString(local_tm.tm_hour) + ":" | 
 | 2729 |             + paddedString(local_tm.tm_min) + ":" | 
 | 2730 |             + paddedString(local_tm.tm_sec); | 
 | 2731 |     this->writeString("on"); | 
 | 2732 |     this->writeSpace(); | 
 | 2733 |     this->writeString(dateTimeStr); | 
 | 2734 |     this->writeString(". Additional documentation and examples can be found at:"); | 
 | 2735 |     this->lfcr(); | 
 | 2736 |     this->writeString("https://skia.org/user/api/"); | 
 | 2737 |     size_t bmhPageStart = bmhName.rfind('/'); | 
 | 2738 |     size_t bmhPageEnd = bmhName.rfind('.'); | 
 | 2739 |     if (string::npos == bmhPageStart || string::npos == bmhPageEnd) { | 
 | 2740 |         return this->reportError<bool>("badly formed bmh page name"); | 
 | 2741 |     } | 
 | 2742 |     ++bmhPageStart; | 
 | 2743 |     string bmhPage = bmhName.substr(bmhPageStart, bmhPageEnd - bmhPageStart); | 
 | 2744 |     this->writeString(bmhPage); | 
 | 2745 |     this->lf(2); | 
 | 2746 |     this->writeString("You may edit either file directly. Structural changes to public interfaces require"); | 
 | 2747 |     this->lfcr(); | 
 | 2748 |     this->writeString("editing both files. After editing"); | 
 | 2749 |     this->writeSpace(); | 
 | 2750 |     this->writeString(bmhName); | 
 | 2751 |     this->writeSpace(); | 
 | 2752 |     this->writeString(", run:"); | 
 | 2753 |     this->lfcr(); | 
 | 2754 |     fIndent += 4; | 
 | 2755 |     this->writeString("bookmaker -b docs -i"); | 
 | 2756 |     this->writeSpace(); | 
 | 2757 |     this->writeString(includeName); | 
 | 2758 |     this->writeSpace(); | 
 | 2759 |     this->writeString("-p"); | 
 | 2760 |     this->lfcr(); | 
 | 2761 |     fIndent -= 4; | 
 | 2762 |     this->writeString("to create an updated version of this file."); | 
 | 2763 |     this->lfcr(); | 
 | 2764 |     fIndent = 1; | 
 | 2765 |     this->writeString("*/"); | 
 | 2766 |     this->lf(2); | 
 | 2767 |     fIndent = 0; | 
| Cary Clark | 27dddae | 2018-06-08 15:57:37 -0400 | [diff] [blame] | 2768 |     if (this->startsWith("/* Generated by tools/bookmaker from")) { | 
 | 2769 |         this->skipToEndBracket("*/"); | 
 | 2770 |         if (!this->skipExact("*/\n\n")) { | 
 | 2771 |             return this->reportError<bool>("malformed generated comment"); | 
 | 2772 |         } | 
 | 2773 |     } | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 2774 |     fStart = fChar; | 
| Cary Clark | 27dddae | 2018-06-08 15:57:37 -0400 | [diff] [blame] | 2775 |  | 
| Cary Clark | b94f6da | 2018-06-08 11:54:32 -0400 | [diff] [blame] | 2776 |     return true; | 
 | 2777 | } |