Home | History | Annotate | Download | only in bookmaker
      1 /*
      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 
     10 static 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 
     23 Definition* FiddleBase::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 
     36 bool FiddleBase::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             do {
     59                 if ('[' == this->peek()) {
     60                     ++brackets;
     61                 } else if (']' == this->peek()) {
     62                     --brackets;
     63                 }
     64             } while (!this->eof() && this->next() && brackets > 0);
     65             this->reportError("fiddle compile error");
     66         }
     67         if (!this->skipExact("],\n")) {
     68             return false;
     69         }
     70         if (!this->skipExact("    \"runtime_error\": \"")) {
     71             return false;
     72         }
     73         if ('"' != this->peek()) {
     74             if (!this->skipToEndBracket('"')) {
     75                 return false;
     76             }
     77             this->reportError("fiddle runtime error");
     78         }
     79         if (!this->skipExact("\",\n")) {
     80             return false;
     81         }
     82         if (!this->skipExact("    \"fiddleHash\": \"")) {
     83             return false;
     84         }
     85         const char* hashStart = fChar;
     86         if (!this->skipToEndBracket('"')) {
     87             return false;
     88         }
     89         Definition* example = this->findExample(name);
     90         if (!example) {
     91             this->reportError("missing example");
     92         }
     93         string hash(hashStart, fChar - hashStart);
     94         if (example) {
     95             example->fHash = hash;
     96         }
     97         if (!this->skipExact("\",\n")) {
     98             return false;
     99         }
    100         if (!this->skipExact("    \"text\": \"")) {
    101             return false;
    102         }
    103         if ('"' != this->peek()) {
    104             const char* stdOutStart = fChar;
    105             do {
    106                 if ('\\' == this->peek()) {
    107                     this->next();
    108                 } else if ('"' == this->peek()) {
    109                     break;
    110                 }
    111             } while (!this->eof() && this->next());
    112             const char* stdOutEnd = fChar;
    113             if (example && fTextOut) {
    114                 if (!this->textOut(example, stdOutStart, stdOutEnd)) {
    115                     return false;
    116                 }
    117             }
    118         } else {
    119             if (example && fPngOut) {
    120                 if (!this->pngOut(example)) {
    121                     return false;
    122                 }
    123             }
    124         }
    125         if (!this->skipExact("\"\n")) {
    126             return false;
    127         }
    128         if (!this->skipExact("  }")) {
    129             return false;
    130         }
    131         if ('\n' == this->peek()) {
    132             break;
    133         }
    134         if (!this->skipExact(",\n")) {
    135             return false;
    136         }
    137     }
    138     return true;
    139 }
    140 
    141 bool FiddleParser::textOut(Definition* example, const char* stdOutStart,
    142         const char* stdOutEnd) {
    143     bool foundStdOut = false;
    144     for (auto& textOut : example->fChildren) {
    145         if (MarkType::kStdOut != textOut->fMarkType) {
    146             continue;
    147         }
    148         foundStdOut = true;
    149         bool foundVolatile = false;
    150         for (auto& stdOutChild : textOut->fChildren) {
    151                 if (MarkType::kVolatile == stdOutChild->fMarkType) {
    152                     foundVolatile = true;
    153                     break;
    154                 }
    155         }
    156         TextParser bmh(textOut);
    157         EscapeParser fiddle(stdOutStart, stdOutEnd);
    158         do {
    159             bmh.skipWhiteSpace();
    160             fiddle.skipWhiteSpace();
    161             const char* bmhEnd = bmh.trimmedLineEnd();
    162             const char* fiddleEnd = fiddle.trimmedLineEnd();
    163             ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
    164             SkASSERT(bmhLen > 0);
    165             ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
    166             SkASSERT(fiddleLen > 0);
    167             if (bmhLen != fiddleLen) {
    168                 if (!foundVolatile) {
    169                     bmh.reportError("mismatched stdout len\n");
    170                 }
    171             } else  if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
    172                 if (!foundVolatile) {
    173                     bmh.reportError("mismatched stdout text\n");
    174                 }
    175             }
    176             bmh.skipToLineStart();
    177             fiddle.skipToLineStart();
    178         } while (!bmh.eof() && !fiddle.eof());
    179         if (!foundStdOut) {
    180             bmh.reportError("bmh %s missing stdout\n");
    181         } else if (!bmh.eof() || !fiddle.eof()) {
    182             if (!foundVolatile) {
    183                 bmh.reportError("%s mismatched stdout eof\n");
    184             }
    185         }
    186     }
    187     return true;
    188 }
    189