aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/bookmaker/fiddleParser.cpp
diff options
context:
space:
mode:
authorGravatar Cary Clark <caryclark@skia.org>2017-07-28 11:04:54 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-07-28 15:30:38 +0000
commit8032b983faaa8c76f81bf3cf028e9c64f4635478 (patch)
treeed3be061ff02a99dab1b3e443d48b7f5c906417e /tools/bookmaker/fiddleParser.cpp
parentacaa607328fb0dfac0894d4a2fcdead520e696b3 (diff)
bookmaker initial checkin
bookmaker is a tool that generates documentation backends from a canonical markup. Documentation for bookmaker itself is evolving at docs/usingBookmaker.bmh, which is visible online at skia.org/user/api/bmh_usingBookmaker Change-Id: Ic76ddf29134895b5c2ebfbc84603e40ff08caf09 Reviewed-on: https://skia-review.googlesource.com/28000 Commit-Queue: Cary Clark <caryclark@google.com> Reviewed-by: Cary Clark <caryclark@google.com>
Diffstat (limited to 'tools/bookmaker/fiddleParser.cpp')
-rw-r--r--tools/bookmaker/fiddleParser.cpp231
1 files changed, 231 insertions, 0 deletions
diff --git a/tools/bookmaker/fiddleParser.cpp b/tools/bookmaker/fiddleParser.cpp
new file mode 100644
index 0000000000..d5cfcf425c
--- /dev/null
+++ b/tools/bookmaker/fiddleParser.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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* FiddleParser::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 FiddleParser::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;
+ const char* errorStart = fChar;
+ do {
+ if ('[' == this->peek()) {
+ ++brackets;
+ } else if (']' == this->peek()) {
+ --brackets;
+ }
+ } while (!this->eof() && this->next() && brackets > 0);
+ SkDebugf("fiddle compile error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
+ errorStart);
+ }
+ if (!this->skipExact("],\n")) {
+ return false;
+ }
+ if (!this->skipExact(" \"runtime_error\": \"")) {
+ return false;
+ }
+ if ('"' != this->peek()) {
+ const char* errorStart = fChar;
+ if (!this->skipToEndBracket('"')) {
+ return false;
+ }
+ SkDebugf("fiddle runtime error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
+ errorStart);
+ }
+ 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) {
+ SkDebugf("missing example %s\n", name.c_str());
+ }
+ 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) {
+ 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) {
+ SkDebugf("mismatched stdout len in %s\n", name.c_str());
+ }
+ } else if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
+ if (!foundVolatile) {
+ SkDebugf("mismatched stdout text in %s\n", name.c_str());
+ }
+ }
+ bmh.skipToLineStart();
+ fiddle.skipToLineStart();
+ } while (!bmh.eof() && !fiddle.eof());
+ if (!foundStdOut) {
+ SkDebugf("bmh %s missing stdout\n", name.c_str());
+ } else if (!bmh.eof() || !fiddle.eof()) {
+ if (!foundVolatile) {
+ SkDebugf("%s mismatched stdout eof\n", name.c_str());
+ }
+ }
+ }
+ }
+ }
+ if (!this->skipExact("\"\n")) {
+ return false;
+ }
+ if (!this->skipExact(" }")) {
+ return false;
+ }
+ if ('\n' == this->peek()) {
+ break;
+ }
+ if (!this->skipExact(",\n")) {
+ return false;
+ }
+ }
+#if 0
+ // compare the text output with the expected output in the markup tree
+ this->skipToSpace();
+ SkASSERT(' ' == fChar[0]);
+ this->next();
+ const char* nameLoc = fChar;
+ this->skipToNonAlphaNum();
+ const char* nameEnd = fChar;
+ string name(nameLoc, nameEnd - nameLoc);
+ const Definition* example = this->findExample(name);
+ if (!example) {
+ return this->reportError<bool>("missing stdout name");
+ }
+ SkASSERT(':' == fChar[0]);
+ this->next();
+ this->skipSpace();
+ const char* stdOutLoc = fChar;
+ do {
+ this->skipToLineStart();
+ } while (!this->eof() && !this->startsWith("fiddles.htm:"));
+ const char* stdOutEnd = fChar;
+ for (auto& textOut : example->fChildren) {
+ if (MarkType::kStdOut != textOut->fMarkType) {
+ continue;
+ }
+ TextParser bmh(textOut);
+ TextParser fiddle(fFileName, stdOutLoc, stdOutEnd, fLineCount);
+ 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) {
+ return this->reportError<bool>("mismatched stdout len");
+ }
+ if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
+ return this->reportError<bool>("mismatched stdout text");
+ }
+ bmh.skipToLineStart();
+ fiddle.skipToLineStart();
+ } while (!bmh.eof() && !fiddle.eof());
+ if (!bmh.eof() || (!fiddle.eof() && !fiddle.startsWith("</pre>"))) {
+ return this->reportError<bool>("mismatched stdout eof");
+ }
+ break;
+ }
+ }
+ }
+#endif
+ return true;
+}