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
TextParser(const Definition * definition)15 TextParser::TextParser(const Definition* definition) :
16 TextParser(definition->fFileName, definition->fContentStart, definition->fContentEnd,
17 definition->fLineCount) {
18 }
19
ReportFilename(string file)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
reportError(const char * errorStr) const34 void TextParser::reportError(const char* errorStr) const {
35 this->reportWarning(errorStr);
36 SkDebugf(""); // convenient place to set a breakpoint
37 }
38
reportWarning(const char * errorStr) const39 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
setForErrorReporting(const Definition * definition,const char * str)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
typedefName()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
skipToMethodEnd(Resolvable resolvable)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