blob: d5cfcf425c9b191eb79f26b06cc64a8d324c59c6 [file] [log] [blame]
Cary Clark8032b982017-07-28 11:04:54 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bookmaker.h"
9
10static Definition* find_fiddle(Definition* def, const string& name) {
11 if (MarkType::kExample == def->fMarkType && name == def->fFiddle) {
12 return def;
13 }
14 for (auto& child : def->fChildren) {
15 Definition* result = find_fiddle(child, name);
16 if (result) {
17 return result;
18 }
19 }
20 return nullptr;
21}
22
23Definition* FiddleParser::findExample(const string& name) const {
24 for (const auto& topic : fBmhParser->fTopicMap) {
25 if (topic.second->fParent) {
26 continue;
27 }
28 Definition* def = find_fiddle(topic.second, name);
29 if (def) {
30 return def;
31 }
32 }
33 return nullptr;
34}
35
36bool FiddleParser::parseFiddles() {
37 if (!this->skipExact("{\n")) {
38 return false;
39 }
40 while (!this->eof()) {
41 if (!this->skipExact(" \"")) {
42 return false;
43 }
44 const char* nameLoc = fChar;
45 if (!this->skipToEndBracket("\"")) {
46 return false;
47 }
48 string name(nameLoc, fChar - nameLoc);
49 if (!this->skipExact("\": {\n")) {
50 return false;
51 }
52 if (!this->skipExact(" \"compile_errors\": [")) {
53 return false;
54 }
55 if (']' != this->peek()) {
56 // report compiler errors
57 int brackets = 1;
58 const char* errorStart = fChar;
59 do {
60 if ('[' == this->peek()) {
61 ++brackets;
62 } else if (']' == this->peek()) {
63 --brackets;
64 }
65 } while (!this->eof() && this->next() && brackets > 0);
66 SkDebugf("fiddle compile error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
67 errorStart);
68 }
69 if (!this->skipExact("],\n")) {
70 return false;
71 }
72 if (!this->skipExact(" \"runtime_error\": \"")) {
73 return false;
74 }
75 if ('"' != this->peek()) {
76 const char* errorStart = fChar;
77 if (!this->skipToEndBracket('"')) {
78 return false;
79 }
80 SkDebugf("fiddle runtime error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
81 errorStart);
82 }
83 if (!this->skipExact("\",\n")) {
84 return false;
85 }
86 if (!this->skipExact(" \"fiddleHash\": \"")) {
87 return false;
88 }
89 const char* hashStart = fChar;
90 if (!this->skipToEndBracket('"')) {
91 return false;
92 }
93 Definition* example = this->findExample(name);
94 if (!example) {
95 SkDebugf("missing example %s\n", name.c_str());
96 }
97 string hash(hashStart, fChar - hashStart);
98 if (example) {
99 example->fHash = hash;
100 }
101 if (!this->skipExact("\",\n")) {
102 return false;
103 }
104 if (!this->skipExact(" \"text\": \"")) {
105 return false;
106 }
107 if ('"' != this->peek()) {
108 const char* stdOutStart = fChar;
109 do {
110 if ('\\' == this->peek()) {
111 this->next();
112 } else if ('"' == this->peek()) {
113 break;
114 }
115 } while (!this->eof() && this->next());
116 const char* stdOutEnd = fChar;
117 if (example) {
118 bool foundStdOut = false;
119 for (auto& textOut : example->fChildren) {
120 if (MarkType::kStdOut != textOut->fMarkType) {
121 continue;
122 }
123 foundStdOut = true;
124 bool foundVolatile = false;
125 for (auto& stdOutChild : textOut->fChildren) {
126 if (MarkType::kVolatile == stdOutChild->fMarkType) {
127 foundVolatile = true;
128 break;
129 }
130 }
131 TextParser bmh(textOut);
132 EscapeParser fiddle(stdOutStart, stdOutEnd);
133 do {
134 bmh.skipWhiteSpace();
135 fiddle.skipWhiteSpace();
136 const char* bmhEnd = bmh.trimmedLineEnd();
137 const char* fiddleEnd = fiddle.trimmedLineEnd();
138 ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
139 SkASSERT(bmhLen > 0);
140 ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
141 SkASSERT(fiddleLen > 0);
142 if (bmhLen != fiddleLen) {
143 if (!foundVolatile) {
144 SkDebugf("mismatched stdout len in %s\n", name.c_str());
145 }
146 } else if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
147 if (!foundVolatile) {
148 SkDebugf("mismatched stdout text in %s\n", name.c_str());
149 }
150 }
151 bmh.skipToLineStart();
152 fiddle.skipToLineStart();
153 } while (!bmh.eof() && !fiddle.eof());
154 if (!foundStdOut) {
155 SkDebugf("bmh %s missing stdout\n", name.c_str());
156 } else if (!bmh.eof() || !fiddle.eof()) {
157 if (!foundVolatile) {
158 SkDebugf("%s mismatched stdout eof\n", name.c_str());
159 }
160 }
161 }
162 }
163 }
164 if (!this->skipExact("\"\n")) {
165 return false;
166 }
167 if (!this->skipExact(" }")) {
168 return false;
169 }
170 if ('\n' == this->peek()) {
171 break;
172 }
173 if (!this->skipExact(",\n")) {
174 return false;
175 }
176 }
177#if 0
178 // compare the text output with the expected output in the markup tree
179 this->skipToSpace();
180 SkASSERT(' ' == fChar[0]);
181 this->next();
182 const char* nameLoc = fChar;
183 this->skipToNonAlphaNum();
184 const char* nameEnd = fChar;
185 string name(nameLoc, nameEnd - nameLoc);
186 const Definition* example = this->findExample(name);
187 if (!example) {
188 return this->reportError<bool>("missing stdout name");
189 }
190 SkASSERT(':' == fChar[0]);
191 this->next();
192 this->skipSpace();
193 const char* stdOutLoc = fChar;
194 do {
195 this->skipToLineStart();
196 } while (!this->eof() && !this->startsWith("fiddles.htm:"));
197 const char* stdOutEnd = fChar;
198 for (auto& textOut : example->fChildren) {
199 if (MarkType::kStdOut != textOut->fMarkType) {
200 continue;
201 }
202 TextParser bmh(textOut);
203 TextParser fiddle(fFileName, stdOutLoc, stdOutEnd, fLineCount);
204 do {
205 bmh.skipWhiteSpace();
206 fiddle.skipWhiteSpace();
207 const char* bmhEnd = bmh.trimmedLineEnd();
208 const char* fiddleEnd = fiddle.trimmedLineEnd();
209 ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
210 SkASSERT(bmhLen > 0);
211 ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
212 SkASSERT(fiddleLen > 0);
213 if (bmhLen != fiddleLen) {
214 return this->reportError<bool>("mismatched stdout len");
215 }
216 if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
217 return this->reportError<bool>("mismatched stdout text");
218 }
219 bmh.skipToLineStart();
220 fiddle.skipToLineStart();
221 } while (!bmh.eof() && !fiddle.eof());
222 if (!bmh.eof() || (!fiddle.eof() && !fiddle.startsWith("</pre>"))) {
223 return this->reportError<bool>("mismatched stdout eof");
224 }
225 break;
226 }
227 }
228 }
229#endif
230 return true;
231}