1 /* 2 * Copyright 2018 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 "definition.h" 9 #include "textParser.h" 10 11 #ifdef SK_BUILD_FOR_WIN 12 #include <Windows.h> 13 #endif 14 15 TextParser::TextParser(const Definition* definition) : 16 TextParser(definition->fFileName, definition->fContentStart, definition->fContentEnd, 17 definition->fLineCount) { 18 } 19 20 string TextParser::ReportFilename(string file) { 21 string fullName; 22 #ifdef SK_BUILD_FOR_WIN 23 TCHAR pathChars[MAX_PATH]; 24 DWORD pathLen = GetCurrentDirectory(MAX_PATH, pathChars); 25 for (DWORD index = 0; index < pathLen; ++index) { 26 fullName += pathChars[index] == (char)pathChars[index] ? (char)pathChars[index] : '?'; 27 } 28 fullName += '\\'; 29 #endif 30 fullName += file; 31 return fullName; 32 } 33 34 void TextParser::reportError(const char* errorStr) const { 35 this->reportWarning(errorStr); 36 SkDebugf(""); // convenient place to set a breakpoint 37 } 38 39 void TextParser::reportWarning(const char* errorStr) const { 40 const char* lineStart = fLine; 41 if (lineStart >= fEnd) { 42 lineStart = fChar; 43 } 44 SkASSERT(lineStart < fEnd); 45 TextParser err(fFileName, lineStart, fEnd, fLineCount); 46 size_t lineLen = this->lineLength(); 47 ptrdiff_t spaces = fChar - lineStart; 48 while (spaces > 0 && (size_t) spaces > lineLen) { 49 ++err.fLineCount; 50 err.fLine += lineLen; 51 spaces -= lineLen; 52 lineLen = err.lineLength(); 53 } 54 string fullName = this->ReportFilename(fFileName); 55 SkDebugf("\n%s(%zd): error: %s\n", fullName.c_str(), err.fLineCount, errorStr); 56 if (0 == lineLen) { 57 SkDebugf("[blank line]\n"); 58 } else { 59 while (lineLen > 0 && '\n' == err.fLine[lineLen - 1]) { 60 --lineLen; 61 } 62 SkDebugf("%.*s\n", (int) lineLen, err.fLine); 63 SkDebugf("%*s^\n", (int) spaces, ""); 64 } 65 } 66 67 void TextParser::setForErrorReporting(const Definition* definition, const char* str) { 68 fFileName = definition->fFileName; 69 fStart = definition->fContentStart; 70 fLine = str; 71 while (fLine > fStart && fLine[-1] != '\n') { 72 --fLine; 73 } 74 fChar = str; 75 fEnd = definition->fContentEnd; 76 fLineCount = definition->fLineCount; 77 const char* lineInc = fStart; 78 while (lineInc < str) { 79 fLineCount += '\n' == *lineInc++; 80 } 81 } 82 83 string TextParser::typedefName() { 84 // look for typedef as one of three forms: 85 // typedef return-type (*NAME)(params); 86 // typedef alias NAME; 87 // typedef std::function<alias> NAME; 88 string builder; 89 const char* end = this->doubleLF(); 90 if (!end) { 91 end = fEnd; 92 } 93 const char* altEnd = this->strnstr("#Typedef ##", end); 94 if (altEnd) { 95 end = this->strnchr('\n', end); 96 } 97 if (!end) { 98 return this->reportError<string>("missing typedef std::function end bracket >"); 99 } 100 bool stdFunction = this->startsWith("std::function"); 101 if (stdFunction) { 102 if (!this->skipToEndBracket('>')) { 103 return this->reportError<string>("missing typedef std::function end bracket >"); 104 } 105 this->next(); 106 this->skipWhiteSpace(); 107 builder += string(fChar, end - fChar); 108 } else { 109 const char* paren = this->strnchr('(', end); 110 if (!paren) { 111 const char* lastWord = nullptr; 112 do { 113 this->skipToWhiteSpace(); 114 if (fChar < end && isspace(fChar[0])) { 115 const char* whiteStart = fChar; 116 this->skipWhiteSpace(); 117 // FIXME: test should be for fMC 118 if ('#' == fChar[0]) { 119 end = whiteStart; 120 break; 121 } 122 lastWord = fChar; 123 } else { 124 break; 125 } 126 } while (true); 127 if (!lastWord) { 128 return this->reportError<string>("missing typedef name"); 129 } 130 builder += string(lastWord, end - lastWord); 131 } else { 132 this->skipTo(paren); 133 this->next(); 134 if ('*' != this->next()) { 135 return this->reportError<string>("missing typedef function asterisk"); 136 } 137 const char* nameStart = fChar; 138 if (!this->skipToEndBracket(')')) { 139 return this->reportError<string>("missing typedef function )"); 140 } 141 builder += string(nameStart, fChar - nameStart); 142 if (!this->skipToEndBracket('(')) { 143 return this->reportError<string>("missing typedef params ("); 144 } 145 if (! this->skipToEndBracket(')')) { 146 return this->reportError<string>("missing typedef params )"); 147 } 148 this->skipTo(end); 149 } 150 } 151 return builder; 152 } 153 154 void MethodParser::skipToMethodEnd(Resolvable resolvable) { 155 if (this->eof()) { 156 return; 157 } 158 string name = fLocalName.length() ? fLocalName : fClassName; 159 if ('~' == this->peek()) { 160 this->next(); 161 if (!this->startsWith(name.c_str())) { 162 --fChar; 163 return; 164 } 165 } 166 if (Resolvable::kSimple != resolvable 167 && Resolvable::kInclude != resolvable 168 && (this->startsWith(name.c_str()) || this->startsWith("operator"))) { 169 const char* ptr = this->anyOf("\n ("); 170 if (ptr && '(' == *ptr && strncmp(ptr, "(...", 4)) { 171 this->skipToEndBracket(')'); 172 SkAssertResult(')' == this->next()); 173 Resolvable::kCode == resolvable && this->skipExact(" const"); 174 return; 175 } 176 } 177 if (this->startsWith("Sk") && this->wordEndsWith(".h")) { // allow include refs 178 this->skipToNonName(); 179 } else { 180 this->skipFullName(); 181 if (this->endsWith("operator")) { 182 const char* ptr = this->anyOf("\n ("); 183 if (ptr && '(' == *ptr) { 184 this->skipToEndBracket(')'); 185 SkAssertResult(')' == this->next()); 186 this->skipExact(" const"); 187 } 188 } 189 } 190 } 191