abaffd85ab
Bookmaker does not require documentation for public symbols described as "deprecated", "private", or "experimental". Adding one of these words (case-insensitive) to the symbol description in the include file tells bookmaker that the bmh file should not include documentation, and the generated markdown should omit it in its indices and descriptions. Symbols marked as "to be deprecated" or "may be deprecated" are still regarded as public and documented. Private notes in the includes that start with TODO: are omitted as well. This CL updated generated includes to describe its symbols accordingly. The includes will be fully regenerated in a future CL. The corresponding documentation has been deleted from the bmh files, and the web markup has been regenerated. TBR=reed@google.com Docs-Preview: https://skia.org/?cl=169830 Bug: skia: Change-Id: Ie6ec3ccdadb7be9ac15db4811823a30948c4af25 Reviewed-on: https://skia-review.googlesource.com/c/169830 Commit-Queue: Cary Clark <caryclark@skia.org> Auto-Submit: Cary Clark <caryclark@skia.org> Reviewed-by: Cary Clark <caryclark@skia.org>
792 lines
21 KiB
C++
792 lines
21 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#ifndef textParser_DEFINED
|
|
#define textParser_DEFINED
|
|
|
|
#include <functional>
|
|
|
|
#include "bookmaker.h"
|
|
|
|
class BmhParser;
|
|
class Definition;
|
|
|
|
class TextParser : public NonAssignable {
|
|
TextParser() {} // only for ParserCommon, TextParserSave
|
|
friend class ParserCommon;
|
|
friend class TextParserSave;
|
|
public:
|
|
virtual ~TextParser() {}
|
|
|
|
TextParser(string fileName, const char* start, const char* end, int lineCount)
|
|
: fFileName(fileName)
|
|
, fStart(start)
|
|
, fLine(start)
|
|
, fChar(start)
|
|
, fEnd(end)
|
|
, fLineCount(lineCount)
|
|
{
|
|
}
|
|
|
|
TextParser(const Definition* );
|
|
|
|
const char* anyOf(const char* str) const {
|
|
const char* ptr = fChar;
|
|
while (ptr < fEnd) {
|
|
if (strchr(str, ptr[0])) {
|
|
return ptr;
|
|
}
|
|
++ptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const char* anyOf(const char* wordStart, const char* wordList[], size_t wordListCount) const {
|
|
const char** wordPtr = wordList;
|
|
const char** wordEnd = wordPtr + wordListCount;
|
|
const size_t matchLen = fChar - wordStart;
|
|
while (wordPtr < wordEnd) {
|
|
const char* word = *wordPtr++;
|
|
if (strlen(word) == matchLen && !strncmp(wordStart, word, matchLen)) {
|
|
return word;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// words must be alpha only
|
|
string anyWord(const vector<string>& wordList, int spaces) const {
|
|
const char* matchStart = fChar;
|
|
do {
|
|
int count = spaces;
|
|
while (matchStart < fEnd && !isalpha(matchStart[0])) {
|
|
++matchStart;
|
|
}
|
|
const char* matchEnd = matchStart;
|
|
const char* nextWord = nullptr;
|
|
while (matchEnd < fEnd) {
|
|
if (isalpha(matchEnd[0])) {
|
|
;
|
|
} else if (' ' == matchEnd[0] && --count >= 0) {
|
|
if (!nextWord) {
|
|
nextWord = matchEnd;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
++matchEnd;
|
|
}
|
|
size_t matchLen = matchEnd - matchStart;
|
|
for (auto word : wordList) {
|
|
if (word.length() != matchLen) {
|
|
continue;
|
|
}
|
|
for (unsigned index = 0; index < matchLen; ++index) {
|
|
if (tolower(matchStart[index]) != word[index]) {
|
|
goto nextWord;
|
|
}
|
|
}
|
|
return word;
|
|
nextWord: ;
|
|
}
|
|
matchStart = nextWord ? nextWord : matchEnd;
|
|
} while (matchStart < fEnd);
|
|
return "";
|
|
}
|
|
|
|
bool back(const char* pattern) {
|
|
size_t len = strlen(pattern);
|
|
const char* start = fChar - len;
|
|
if (start <= fStart) {
|
|
return false;
|
|
}
|
|
if (strncmp(start, pattern, len)) {
|
|
return false;
|
|
}
|
|
fChar = start;
|
|
return true;
|
|
}
|
|
|
|
char backup(const char* pattern) const {
|
|
size_t len = strlen(pattern);
|
|
const char* start = fChar - len;
|
|
if (start <= fStart) {
|
|
return '\0';
|
|
}
|
|
if (strncmp(start, pattern, len)) {
|
|
return '\0';
|
|
}
|
|
return start[-1];
|
|
}
|
|
|
|
void backupWord() {
|
|
while (fChar > fStart && isalpha(fChar[-1])) {
|
|
--fChar;
|
|
}
|
|
}
|
|
|
|
bool contains(const char* match, const char* lineEnd, const char** loc) const {
|
|
const char* result = this->strnstr(match, lineEnd);
|
|
if (loc) {
|
|
*loc = result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool containsWord(const char* match, const char* lineEnd, const char** loc) {
|
|
size_t len = strlen(match);
|
|
do {
|
|
const char* result = this->strnstr(match, lineEnd);
|
|
if (!result) {
|
|
return false;
|
|
}
|
|
if ((result > fStart && isalnum(result[-1])) || (result + len < fEnd
|
|
&& isalnum(result[len]))) {
|
|
fChar = result + len;
|
|
continue;
|
|
}
|
|
if (loc) {
|
|
*loc = result;
|
|
}
|
|
return true;
|
|
} while (true);
|
|
}
|
|
|
|
// either /n/n or /n# will stop parsing a typedef
|
|
const char* doubleLF() const {
|
|
const char* ptr = fChar - 1;
|
|
const char* doubleStart = nullptr;
|
|
while (++ptr < fEnd) {
|
|
if (!doubleStart) {
|
|
if ('\n' == ptr[0]) {
|
|
doubleStart = ptr;
|
|
}
|
|
continue;
|
|
}
|
|
if ('\n' == ptr[0] || '#' == ptr[0]) {
|
|
return doubleStart;
|
|
}
|
|
if (' ' < ptr[0]) {
|
|
doubleStart = nullptr;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool endsWith(const char* match) {
|
|
int matchLen = strlen(match);
|
|
if (matchLen > fChar - fLine) {
|
|
return false;
|
|
}
|
|
return !strncmp(fChar - matchLen, match, matchLen);
|
|
}
|
|
|
|
bool eof() const { return fChar >= fEnd; }
|
|
|
|
const char* lineEnd() const {
|
|
const char* ptr = fChar;
|
|
do {
|
|
if (ptr >= fEnd) {
|
|
return ptr;
|
|
}
|
|
char test = *ptr++;
|
|
if (test == '\n' || test == '\0') {
|
|
break;
|
|
}
|
|
} while (true);
|
|
return ptr;
|
|
}
|
|
|
|
ptrdiff_t lineLength() const {
|
|
return this->lineEnd() - fLine;
|
|
}
|
|
|
|
bool match(TextParser* );
|
|
|
|
char next() {
|
|
SkASSERT(fChar < fEnd);
|
|
char result = *fChar++;
|
|
if ('\n' == result) {
|
|
++fLineCount;
|
|
fLine = fChar;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
char peek() const { SkASSERT(fChar < fEnd); return *fChar; }
|
|
|
|
void restorePlace(const TextParser& save) {
|
|
fChar = save.fChar;
|
|
fLine = save.fLine;
|
|
fLineCount = save.fLineCount;
|
|
}
|
|
|
|
void savePlace(TextParser* save) {
|
|
save->fChar = fChar;
|
|
save->fLine = fLine;
|
|
save->fLineCount = fLineCount;
|
|
}
|
|
|
|
void reportError(const char* errorStr) const;
|
|
static string ReportFilename(string file);
|
|
void reportWarning(const char* errorStr) const;
|
|
|
|
template <typename T> T reportError(const char* errorStr) const {
|
|
this->reportError(errorStr);
|
|
return T();
|
|
}
|
|
|
|
bool sentenceEnd(const char* check) const {
|
|
while (check > fStart) {
|
|
--check;
|
|
if (' ' < check[0] && '.' != check[0]) {
|
|
return false;
|
|
}
|
|
if ('.' == check[0]) {
|
|
return ' ' >= check[1];
|
|
}
|
|
if ('\n' == check[0] && '\n' == check[1]) {
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void setForErrorReporting(const Definition* , const char* );
|
|
|
|
bool skipToBalancedEndBracket(char startB, char endB) {
|
|
SkASSERT(fChar < fEnd);
|
|
SkASSERT(startB == fChar[0]);
|
|
int startCount = 0;
|
|
do {
|
|
char test = this->next();
|
|
startCount += startB == test;
|
|
startCount -= endB == test;
|
|
} while (startCount && fChar < fEnd);
|
|
return !startCount;
|
|
}
|
|
|
|
bool skipToEndBracket(char endBracket, const char* end = nullptr) {
|
|
if (nullptr == end) {
|
|
end = fEnd;
|
|
}
|
|
while (fChar[0] != endBracket) {
|
|
if (fChar >= end) {
|
|
return false;
|
|
}
|
|
(void) this->next();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool skipToEndBracket(const char* endBracket) {
|
|
size_t len = strlen(endBracket);
|
|
while (strncmp(fChar, endBracket, len)) {
|
|
if (fChar >= fEnd) {
|
|
return false;
|
|
}
|
|
(void) this->next();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool skipLine() {
|
|
return skipToEndBracket('\n');
|
|
}
|
|
|
|
void skipTo(const char* skip) {
|
|
while (fChar < skip) {
|
|
this->next();
|
|
}
|
|
}
|
|
|
|
void skipToAlpha() {
|
|
while (fChar < fEnd && !isalpha(fChar[0])) {
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
// returns true if saw close brace
|
|
bool skipToAlphaNum() {
|
|
bool sawCloseBrace = false;
|
|
while (fChar < fEnd && !isalnum(fChar[0])) {
|
|
sawCloseBrace |= '}' == *fChar++;
|
|
}
|
|
return sawCloseBrace;
|
|
}
|
|
|
|
bool skipExact(const char* pattern) {
|
|
if (!this->startsWith(pattern)) {
|
|
return false;
|
|
}
|
|
this->skipName(pattern);
|
|
return true;
|
|
}
|
|
|
|
// differs from skipToNonAlphaNum in that a.b isn't considered a full name,
|
|
// since a.b can't be found as a named definition
|
|
void skipFullName() {
|
|
do {
|
|
char last = '\0';
|
|
while (fChar < fEnd && (isalnum(fChar[0])
|
|
|| '_' == fChar[0] /* || '-' == fChar[0] */
|
|
|| (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1]))) {
|
|
if (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1]) {
|
|
fChar++;
|
|
}
|
|
last = fChar[0];
|
|
fChar++;
|
|
}
|
|
if (fChar + 1 >= fEnd || '/' != fChar[0] || !isalpha(last) || !isalpha(fChar[1])) {
|
|
break; // stop unless pattern is xxx/xxx as in I/O
|
|
}
|
|
fChar++; // skip slash
|
|
} while (true);
|
|
}
|
|
|
|
int skipToLineBalance(char open, char close) {
|
|
int match = 0;
|
|
while (!this->eof() && '\n' != fChar[0]) {
|
|
match += open == this->peek();
|
|
match -= close == this->next();
|
|
}
|
|
return match;
|
|
}
|
|
|
|
bool skipToLineStart() {
|
|
if (!this->skipLine()) {
|
|
return false;
|
|
}
|
|
if (!this->eof()) {
|
|
return this->skipWhiteSpace();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void skipToLineStart(int* indent, bool* sawReturn) {
|
|
SkAssertResult(this->skipLine());
|
|
this->skipWhiteSpace(indent, sawReturn);
|
|
}
|
|
|
|
void skipLower() {
|
|
while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
void skipToNonAlphaNum() {
|
|
while (fChar < fEnd && (isalnum(fChar[0]) || '_' == fChar[0])) {
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
void skipToNonName() {
|
|
while (fChar < fEnd && (isalnum(fChar[0])
|
|
|| '_' == fChar[0] || '-' == fChar[0]
|
|
|| (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
|
|
|| ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
|
|
if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
|
|
fChar++;
|
|
}
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
void skipPhraseName() {
|
|
while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
void skipToSpace() {
|
|
while (fChar < fEnd && ' ' != fChar[0]) {
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
void skipToWhiteSpace() {
|
|
while (fChar < fEnd && ' ' < fChar[0]) {
|
|
fChar++;
|
|
}
|
|
}
|
|
|
|
bool skipName(const char* word) {
|
|
size_t len = strlen(word);
|
|
if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
|
|
for (size_t i = 0; i < len; ++i) {
|
|
this->next();
|
|
}
|
|
}
|
|
return this->eof() || ' ' >= fChar[0];
|
|
}
|
|
|
|
bool skipSpace() {
|
|
while (' ' == this->peek()) {
|
|
(void) this->next();
|
|
if (fChar >= fEnd) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool skipWord(const char* word) {
|
|
if (!this->skipWhiteSpace()) {
|
|
return false;
|
|
}
|
|
const char* save = fChar;
|
|
if (!this->skipName(word)) {
|
|
fChar = save;
|
|
return false;
|
|
}
|
|
if (!this->skipWhiteSpace()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool skipWhiteSpace() {
|
|
while (' ' >= this->peek()) {
|
|
(void) this->next();
|
|
if (fChar >= fEnd) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void skipWhiteSpace(int* indent, bool* skippedReturn) {
|
|
while (' ' >= this->peek()) {
|
|
*indent = *skippedReturn ? *indent + 1 : 1;
|
|
if ('\n' == this->peek()) {
|
|
*skippedReturn |= true;
|
|
*indent = 0;
|
|
}
|
|
(void) this->next();
|
|
SkASSERT(fChar < fEnd);
|
|
}
|
|
}
|
|
|
|
bool startsWith(const char* str) const {
|
|
size_t len = strlen(str);
|
|
ptrdiff_t lineLen = fEnd - fChar;
|
|
return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
|
|
}
|
|
|
|
// ignores minor white space differences
|
|
bool startsWith(const char* str, size_t oLen) const {
|
|
size_t tIndex = 0;
|
|
size_t tLen = fEnd - fChar;
|
|
size_t oIndex = 0;
|
|
while (oIndex < oLen && tIndex < tLen) {
|
|
bool tSpace = ' ' >= fChar[tIndex];
|
|
bool oSpace = ' ' >= str[oIndex];
|
|
if (tSpace != oSpace) {
|
|
break;
|
|
}
|
|
if (tSpace) {
|
|
do {
|
|
++tIndex;
|
|
} while (tIndex < tLen && ' ' >= fChar[tIndex]);
|
|
do {
|
|
++oIndex;
|
|
} while (oIndex < oLen && ' ' >= str[oIndex]);
|
|
continue;
|
|
}
|
|
if (fChar[tIndex] != str[oIndex]) {
|
|
break;
|
|
}
|
|
++tIndex;
|
|
++oIndex;
|
|
}
|
|
return oIndex >= oLen;
|
|
}
|
|
|
|
const char* strnchr(char ch, const char* end) const {
|
|
const char* ptr = fChar;
|
|
while (ptr < end) {
|
|
if (ptr[0] == ch) {
|
|
return ptr;
|
|
}
|
|
++ptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const char* strnstr(const char *match, const char* end) const {
|
|
size_t matchLen = strlen(match);
|
|
SkASSERT(matchLen > 0);
|
|
ptrdiff_t len = end - fChar;
|
|
SkASSERT(len >= 0);
|
|
if ((size_t) len < matchLen ) {
|
|
return nullptr;
|
|
}
|
|
size_t count = len - matchLen;
|
|
for (size_t index = 0; index <= count; index++) {
|
|
if (0 == strncmp(&fChar[index], match, matchLen)) {
|
|
return &fChar[index];
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const char* trimmedBracketEnd(const char bracket) const {
|
|
int max = (int) (this->lineLength());
|
|
int index = 0;
|
|
while (index < max && bracket != fChar[index]) {
|
|
++index;
|
|
}
|
|
SkASSERT(index < max);
|
|
while (index > 0 && ' ' >= fChar[index - 1]) {
|
|
--index;
|
|
}
|
|
return fChar + index;
|
|
}
|
|
|
|
const char* trimmedBracketEnd(string bracket) const {
|
|
size_t max = (size_t) (this->lineLength());
|
|
string line(fChar, max);
|
|
size_t index = line.find(bracket);
|
|
SkASSERT(index < max);
|
|
while (index > 0 && ' ' >= fChar[index - 1]) {
|
|
--index;
|
|
}
|
|
return fChar + index;
|
|
}
|
|
|
|
const char* trimmedBracketNoEnd(const char bracket) const {
|
|
int max = (int) (fEnd - fChar);
|
|
int index = 0;
|
|
while (index < max && bracket != fChar[index]) {
|
|
++index;
|
|
}
|
|
SkASSERT(index < max);
|
|
while (index > 0 && ' ' >= fChar[index - 1]) {
|
|
--index;
|
|
}
|
|
return fChar + index;
|
|
}
|
|
|
|
const char* trimmedLineEnd() const {
|
|
const char* result = this->lineEnd();
|
|
while (result > fChar && ' ' >= result[-1]) {
|
|
--result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void trimEnd() {
|
|
while (fEnd > fStart && ' ' >= fEnd[-1]) {
|
|
--fEnd;
|
|
}
|
|
}
|
|
|
|
// FIXME: nothing else in TextParser knows from C++ --
|
|
// there could be a class between TextParser and ParserCommon
|
|
virtual string typedefName();
|
|
|
|
const char* wordEnd() const {
|
|
const char* end = fChar;
|
|
while (isalnum(end[0]) || '_' == end[0] || '-' == end[0]) {
|
|
++end;
|
|
}
|
|
return end;
|
|
}
|
|
|
|
string fFileName;
|
|
const char* fStart;
|
|
const char* fLine;
|
|
const char* fChar;
|
|
const char* fEnd;
|
|
size_t fLineCount;
|
|
};
|
|
|
|
class TextParserSave {
|
|
public:
|
|
TextParserSave(TextParser* parser) {
|
|
fParser = parser;
|
|
fSave.fFileName = parser->fFileName;
|
|
fSave.fStart = parser->fStart;
|
|
fSave.fLine = parser->fLine;
|
|
fSave.fChar = parser->fChar;
|
|
fSave.fEnd = parser->fEnd;
|
|
fSave.fLineCount = parser->fLineCount;
|
|
}
|
|
|
|
void restore() const {
|
|
fParser->fFileName = fSave.fFileName;
|
|
fParser->fStart = fSave.fStart;
|
|
fParser->fLine = fSave.fLine;
|
|
fParser->fChar = fSave.fChar;
|
|
fParser->fEnd = fSave.fEnd;
|
|
fParser->fLineCount = fSave.fLineCount;
|
|
}
|
|
|
|
private:
|
|
TextParser* fParser;
|
|
TextParser fSave;
|
|
};
|
|
|
|
static inline bool has_nonwhitespace(string s) {
|
|
bool nonwhite = false;
|
|
for (const char& c : s) {
|
|
if (' ' < c) {
|
|
nonwhite = true;
|
|
break;
|
|
}
|
|
}
|
|
return nonwhite;
|
|
}
|
|
|
|
static inline void trim_end(string &s) {
|
|
s.erase(std::find_if(s.rbegin(), s.rend(),
|
|
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
|
}
|
|
|
|
static inline void trim_end_spaces(string &s) {
|
|
while (s.length() > 0 && ' ' == s.back()) {
|
|
s.pop_back();
|
|
}
|
|
}
|
|
|
|
static inline void trim_start(string &s) {
|
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
|
|
std::not1(std::ptr_fun<int, int>(std::isspace))));
|
|
}
|
|
|
|
static inline void trim_start_end(string& s) {
|
|
trim_start(s);
|
|
trim_end(s);
|
|
}
|
|
|
|
static inline string trim_inline_spaces(string s) {
|
|
bool lastSpace = false;
|
|
string trimmed;
|
|
for (const char* ptr = &s.front(); ptr <= &s.back(); ++ptr) {
|
|
char c = *ptr;
|
|
if (' ' >= c) {
|
|
if (!lastSpace) {
|
|
trimmed += ' ';
|
|
}
|
|
lastSpace = true;
|
|
continue;
|
|
}
|
|
lastSpace = false;
|
|
trimmed += c;
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
class EscapeParser : public TextParser {
|
|
public:
|
|
EscapeParser(const char* start, const char* end) :
|
|
TextParser("", start, end, 0) {
|
|
const char* reader = fStart;
|
|
fStorage = new char[end - start];
|
|
char* writer = fStorage;
|
|
while (reader < fEnd) {
|
|
char ch = *reader++;
|
|
if (ch != '\\') {
|
|
*writer++ = ch;
|
|
} else {
|
|
char ctrl = *reader++;
|
|
if (ctrl == 'u') {
|
|
unsigned unicode = 0;
|
|
for (int i = 0; i < 4; ++i) {
|
|
unicode <<= 4;
|
|
SkASSERT((reader[0] >= '0' && reader[0] <= '9') ||
|
|
(reader[0] >= 'A' && reader[0] <= 'F') ||
|
|
(reader[0] >= 'a' && reader[0] <= 'f'));
|
|
int nibble = *reader++ - '0';
|
|
if (nibble > 9) {
|
|
nibble = (nibble & ~('a' - 'A')) - 'A' + '9' + 1;
|
|
}
|
|
unicode |= nibble;
|
|
}
|
|
SkASSERT(unicode < 256);
|
|
*writer++ = (unsigned char) unicode;
|
|
} else {
|
|
SkASSERT(ctrl == 'n');
|
|
*writer++ = '\n';
|
|
}
|
|
}
|
|
}
|
|
fStart = fLine = fChar = fStorage;
|
|
fEnd = writer;
|
|
}
|
|
|
|
~EscapeParser() override {
|
|
delete fStorage;
|
|
}
|
|
private:
|
|
char* fStorage;
|
|
};
|
|
|
|
// some methods cannot be trivially parsed; look for class-name / ~ / operator
|
|
class MethodParser : public TextParser {
|
|
public:
|
|
MethodParser(string className, string fileName,
|
|
const char* start, const char* end, int lineCount)
|
|
: TextParser(fileName, start, end, lineCount)
|
|
, fClassName(className) {
|
|
size_t doubleColons = className.find_last_of("::");
|
|
if (string::npos != doubleColons) {
|
|
fLocalName = className.substr(doubleColons + 1);
|
|
SkASSERT(fLocalName.length() > 0);
|
|
}
|
|
}
|
|
|
|
~MethodParser() override {}
|
|
|
|
string localName() const {
|
|
return fLocalName;
|
|
}
|
|
|
|
void setLocalName(string name) {
|
|
if (name == fClassName) {
|
|
fLocalName = "";
|
|
} else {
|
|
fLocalName = name;
|
|
}
|
|
}
|
|
|
|
// returns true if close brace was skipped
|
|
int skipToMethodStart() {
|
|
if (!fClassName.length()) {
|
|
return this->skipToAlphaNum();
|
|
}
|
|
int braceCount = 0;
|
|
while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
|
|
braceCount += '{' == this->peek();
|
|
braceCount -= '}' == this->peek();
|
|
this->next();
|
|
}
|
|
return braceCount;
|
|
}
|
|
|
|
void skipToMethodEnd(Resolvable resolvable);
|
|
|
|
bool wordEndsWith(const char* str) const {
|
|
const char* space = this->strnchr(' ', fEnd);
|
|
if (!space) {
|
|
return false;
|
|
}
|
|
size_t len = strlen(str);
|
|
if (space < fChar + len) {
|
|
return false;
|
|
}
|
|
return !strncmp(str, space - len, len);
|
|
}
|
|
|
|
private:
|
|
string fClassName;
|
|
string fLocalName;
|
|
typedef TextParser INHERITED;
|
|
};
|
|
|
|
#endif
|