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