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