| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "bookmaker.h" |
| |
| static Definition* find_fiddle(Definition* def, const string& name) { |
| if (MarkType::kExample == def->fMarkType && name == def->fFiddle) { |
| return def; |
| } |
| for (auto& child : def->fChildren) { |
| Definition* result = find_fiddle(child, name); |
| if (result) { |
| return result; |
| } |
| } |
| return nullptr; |
| } |
| |
| Definition* FiddleBase::findExample(const string& name) const { |
| for (const auto& topic : fBmhParser->fTopicMap) { |
| if (topic.second->fParent) { |
| continue; |
| } |
| Definition* def = find_fiddle(topic.second, name); |
| if (def) { |
| return def; |
| } |
| } |
| return nullptr; |
| } |
| |
| bool FiddleBase::parseFiddles() { |
| if (!this->skipExact("{\n")) { |
| return false; |
| } |
| while (!this->eof()) { |
| if (!this->skipExact(" \"")) { |
| return false; |
| } |
| const char* nameLoc = fChar; |
| if (!this->skipToEndBracket("\"")) { |
| return false; |
| } |
| string name(nameLoc, fChar - nameLoc); |
| if (!this->skipExact("\": {\n")) { |
| return false; |
| } |
| if (!this->skipExact(" \"compile_errors\": [")) { |
| return false; |
| } |
| if (']' != this->peek()) { |
| // report compiler errors |
| int brackets = 1; |
| do { |
| if ('[' == this->peek()) { |
| ++brackets; |
| } else if (']' == this->peek()) { |
| --brackets; |
| } |
| } while (!this->eof() && this->next() && brackets > 0); |
| this->reportError("fiddle compile error"); |
| } |
| if (!this->skipExact("],\n")) { |
| return false; |
| } |
| if (!this->skipExact(" \"runtime_error\": \"")) { |
| return false; |
| } |
| if ('"' != this->peek()) { |
| if (!this->skipToEndBracket('"')) { |
| return false; |
| } |
| this->reportError("fiddle runtime error"); |
| } |
| if (!this->skipExact("\",\n")) { |
| return false; |
| } |
| if (!this->skipExact(" \"fiddleHash\": \"")) { |
| return false; |
| } |
| const char* hashStart = fChar; |
| if (!this->skipToEndBracket('"')) { |
| return false; |
| } |
| Definition* example = this->findExample(name); |
| if (!example) { |
| this->reportError("missing example"); |
| } |
| string hash(hashStart, fChar - hashStart); |
| if (example) { |
| example->fHash = hash; |
| } |
| if (!this->skipExact("\",\n")) { |
| return false; |
| } |
| if (!this->skipExact(" \"text\": \"")) { |
| return false; |
| } |
| if ('"' != this->peek()) { |
| const char* stdOutStart = fChar; |
| do { |
| if ('\\' == this->peek()) { |
| this->next(); |
| } else if ('"' == this->peek()) { |
| break; |
| } |
| } while (!this->eof() && this->next()); |
| const char* stdOutEnd = fChar; |
| if (example && fTextOut) { |
| if (!this->textOut(example, stdOutStart, stdOutEnd)) { |
| return false; |
| } |
| } |
| } else { |
| if (example && fPngOut) { |
| if (!this->pngOut(example)) { |
| return false; |
| } |
| } |
| } |
| if (!this->skipExact("\"\n")) { |
| return false; |
| } |
| if (!this->skipExact(" }")) { |
| return false; |
| } |
| if ('\n' == this->peek()) { |
| break; |
| } |
| if (!this->skipExact(",\n")) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool FiddleParser::textOut(Definition* example, const char* stdOutStart, |
| const char* stdOutEnd) { |
| bool foundStdOut = false; |
| for (auto& textOut : example->fChildren) { |
| if (MarkType::kStdOut != textOut->fMarkType) { |
| continue; |
| } |
| foundStdOut = true; |
| bool foundVolatile = false; |
| for (auto& stdOutChild : textOut->fChildren) { |
| if (MarkType::kVolatile == stdOutChild->fMarkType) { |
| foundVolatile = true; |
| break; |
| } |
| } |
| TextParser bmh(textOut); |
| EscapeParser fiddle(stdOutStart, stdOutEnd); |
| do { |
| bmh.skipWhiteSpace(); |
| fiddle.skipWhiteSpace(); |
| const char* bmhEnd = bmh.trimmedLineEnd(); |
| const char* fiddleEnd = fiddle.trimmedLineEnd(); |
| ptrdiff_t bmhLen = bmhEnd - bmh.fChar; |
| SkASSERT(bmhLen > 0); |
| ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar; |
| SkASSERT(fiddleLen > 0); |
| if (bmhLen != fiddleLen) { |
| if (!foundVolatile) { |
| bmh.reportError("mismatched stdout len\n"); |
| } |
| } else if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) { |
| if (!foundVolatile) { |
| bmh.reportError("mismatched stdout text\n"); |
| } |
| } |
| bmh.skipToLineStart(); |
| fiddle.skipToLineStart(); |
| } while (!bmh.eof() && !fiddle.eof()); |
| if (!foundStdOut) { |
| bmh.reportError("bmh %s missing stdout\n"); |
| } else if (!bmh.eof() || !fiddle.eof()) { |
| if (!foundVolatile) { |
| bmh.reportError("%s mismatched stdout eof\n"); |
| } |
| } |
| } |
| return true; |
| } |