2017-07-28 15:04:54 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2017 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef bookmaker_DEFINED
|
|
|
|
#define bookmaker_DEFINED
|
|
|
|
|
2017-09-01 19:51:02 +00:00
|
|
|
#include "SkCommandLineFlags.h"
|
2017-07-28 15:04:54 +00:00
|
|
|
#include "SkData.h"
|
2017-12-11 21:03:17 +00:00
|
|
|
#include "SkJSONCPP.h"
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2017-10-09 19:45:33 +00:00
|
|
|
#include <algorithm>
|
2017-07-28 15:04:54 +00:00
|
|
|
#include <cmath>
|
|
|
|
#include <cctype>
|
|
|
|
#include <forward_list>
|
|
|
|
#include <list>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
// std::to_string isn't implemented on android
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::string to_string(T value)
|
|
|
|
{
|
|
|
|
std::ostringstream os ;
|
|
|
|
os << value ;
|
|
|
|
return os.str() ;
|
|
|
|
}
|
|
|
|
|
|
|
|
using std::forward_list;
|
|
|
|
using std::list;
|
|
|
|
using std::unordered_map;
|
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
|
|
|
|
enum class KeyWord {
|
|
|
|
kNone,
|
2017-08-29 21:36:51 +00:00
|
|
|
kSK_API,
|
2017-10-26 11:58:48 +00:00
|
|
|
kSK_BEGIN_REQUIRE_DENSE,
|
2017-07-28 15:04:54 +00:00
|
|
|
kBool,
|
|
|
|
kChar,
|
|
|
|
kClass,
|
|
|
|
kConst,
|
|
|
|
kConstExpr,
|
|
|
|
kDefine,
|
|
|
|
kDouble,
|
|
|
|
kElif,
|
|
|
|
kElse,
|
|
|
|
kEndif,
|
|
|
|
kEnum,
|
2018-01-26 17:56:22 +00:00
|
|
|
kError,
|
2017-07-28 15:04:54 +00:00
|
|
|
kFloat,
|
|
|
|
kFriend,
|
|
|
|
kIf,
|
|
|
|
kIfdef,
|
|
|
|
kIfndef,
|
|
|
|
kInclude,
|
|
|
|
kInline,
|
|
|
|
kInt,
|
|
|
|
kOperator,
|
|
|
|
kPrivate,
|
|
|
|
kProtected,
|
|
|
|
kPublic,
|
|
|
|
kSigned,
|
|
|
|
kSize_t,
|
|
|
|
kStatic,
|
|
|
|
kStruct,
|
|
|
|
kTemplate,
|
|
|
|
kTypedef,
|
2018-06-07 13:59:07 +00:00
|
|
|
kTypename,
|
2017-09-14 15:25:39 +00:00
|
|
|
kUint16_t,
|
2017-07-28 15:04:54 +00:00
|
|
|
kUint32_t,
|
2017-09-14 15:25:39 +00:00
|
|
|
kUint64_t,
|
|
|
|
kUint8_t,
|
2018-05-21 15:56:57 +00:00
|
|
|
kUintPtr_t,
|
2017-07-28 15:04:54 +00:00
|
|
|
kUnion,
|
|
|
|
kUnsigned,
|
|
|
|
kVoid,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class MarkType {
|
|
|
|
kNone,
|
|
|
|
kAnchor,
|
|
|
|
kAlias,
|
|
|
|
kBug,
|
|
|
|
kClass,
|
|
|
|
kCode,
|
|
|
|
kColumn,
|
|
|
|
kComment,
|
|
|
|
kConst,
|
|
|
|
kDefine,
|
|
|
|
kDeprecated,
|
|
|
|
kDescription,
|
2018-05-16 11:07:07 +00:00
|
|
|
kDetails, // used by #Const to specify #Subtopic details with examples and so on
|
2018-01-11 15:35:44 +00:00
|
|
|
kDuration,
|
2017-07-28 15:04:54 +00:00
|
|
|
kEnum,
|
|
|
|
kEnumClass,
|
|
|
|
kExample,
|
|
|
|
kExperimental,
|
|
|
|
kExternal,
|
2018-06-07 13:59:07 +00:00
|
|
|
kFile,
|
2017-07-28 15:04:54 +00:00
|
|
|
kFormula,
|
|
|
|
kFunction,
|
|
|
|
kHeight,
|
2018-02-27 14:54:21 +00:00
|
|
|
kIllustration,
|
2017-07-28 15:04:54 +00:00
|
|
|
kImage,
|
2018-01-30 15:08:57 +00:00
|
|
|
kIn,
|
2017-07-28 15:04:54 +00:00
|
|
|
kLegend,
|
2018-01-30 15:08:57 +00:00
|
|
|
kLine,
|
2018-06-27 15:00:21 +00:00
|
|
|
kLink, // used internally by #Anchor
|
2017-07-28 15:04:54 +00:00
|
|
|
kList,
|
2017-10-26 11:58:48 +00:00
|
|
|
kLiteral, // don't lookup hyperlinks, do substitution, etc
|
2017-07-28 15:04:54 +00:00
|
|
|
kMarkChar,
|
|
|
|
kMember,
|
|
|
|
kMethod,
|
|
|
|
kNoExample,
|
2018-05-16 11:07:07 +00:00
|
|
|
kNoJustify, // don't contribute this #Line to tabular comment measure, even if it fits
|
2017-10-26 11:58:48 +00:00
|
|
|
kOutdent,
|
2017-07-28 15:04:54 +00:00
|
|
|
kParam,
|
2018-03-05 18:26:16 +00:00
|
|
|
kPhraseDef,
|
2018-05-16 11:07:07 +00:00
|
|
|
kPhraseParam,
|
2018-03-05 18:26:16 +00:00
|
|
|
kPhraseRef,
|
2017-07-28 15:04:54 +00:00
|
|
|
kPlatform,
|
2018-02-01 14:37:32 +00:00
|
|
|
kPopulate,
|
2017-07-28 15:04:54 +00:00
|
|
|
kPrivate,
|
|
|
|
kReturn,
|
|
|
|
kRow,
|
|
|
|
kSeeAlso,
|
2018-01-03 13:37:53 +00:00
|
|
|
kSet,
|
2017-07-28 15:04:54 +00:00
|
|
|
kStdOut,
|
|
|
|
kStruct,
|
|
|
|
kSubstitute,
|
|
|
|
kSubtopic,
|
|
|
|
kTable,
|
|
|
|
kTemplate,
|
|
|
|
kText,
|
|
|
|
kToDo,
|
|
|
|
kTopic,
|
|
|
|
kTypedef,
|
|
|
|
kUnion,
|
|
|
|
kVolatile,
|
|
|
|
kWidth,
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
static inline bool IncompleteAllowed(MarkType markType) {
|
|
|
|
return MarkType::kDeprecated == markType || MarkType::kExperimental == markType;
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
enum {
|
|
|
|
Last_MarkType = (int) MarkType::kWidth,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class Bracket {
|
|
|
|
kNone,
|
|
|
|
kParen,
|
|
|
|
kSquare,
|
|
|
|
kBrace,
|
|
|
|
kAngle,
|
|
|
|
kString,
|
|
|
|
kChar,
|
|
|
|
kSlashStar,
|
|
|
|
kSlashSlash,
|
|
|
|
kPound,
|
|
|
|
kColon,
|
2017-08-29 21:36:51 +00:00
|
|
|
kDebugCode, // parens get special treatment so SkDEBUGCODE( isn't treated as method
|
2017-07-28 15:04:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class Punctuation { // catch-all for misc symbols tracked in C
|
|
|
|
kNone,
|
|
|
|
kAsterisk, // for pointer-to
|
|
|
|
kSemicolon, // e.g., to delinate xxx() const ; const int* yyy()
|
|
|
|
kLeftBrace,
|
|
|
|
kColon, // for foo() : bar(1), baz(2) {}
|
|
|
|
};
|
|
|
|
|
2017-09-14 15:25:39 +00:00
|
|
|
enum class KeyProperty {
|
|
|
|
kNone,
|
|
|
|
kClassSection,
|
|
|
|
kFunction,
|
|
|
|
kModifier,
|
|
|
|
kNumber,
|
|
|
|
kObject,
|
|
|
|
kPreprocessor,
|
|
|
|
};
|
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
enum class StatusFilter {
|
|
|
|
kCompleted,
|
|
|
|
kInProgress,
|
|
|
|
kUnknown,
|
|
|
|
};
|
|
|
|
|
2017-09-14 15:25:39 +00:00
|
|
|
struct IncludeKey {
|
|
|
|
const char* fName;
|
|
|
|
KeyWord fKeyWord;
|
|
|
|
KeyProperty fProperty;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern const IncludeKey kKeyWords[];
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
static inline bool has_nonwhitespace(string s) {
|
2017-07-28 15:04:54 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
class NonAssignable {
|
|
|
|
public:
|
|
|
|
NonAssignable(NonAssignable const&) = delete;
|
|
|
|
NonAssignable& operator=(NonAssignable const&) = delete;
|
|
|
|
NonAssignable() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Definition;
|
|
|
|
|
|
|
|
class TextParser : public NonAssignable {
|
2018-04-03 12:43:27 +00:00
|
|
|
TextParser() {} // only for ParserCommon, TextParserSave
|
2017-07-28 15:04:54 +00:00
|
|
|
friend class ParserCommon;
|
2018-04-03 12:43:27 +00:00
|
|
|
friend class TextParserSave;
|
2017-07-28 15:04:54 +00:00
|
|
|
public:
|
2017-12-11 21:03:17 +00:00
|
|
|
virtual ~TextParser() {}
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
TextParser(string fileName, const char* start, const char* end, int lineCount)
|
2017-07-28 15:04:54 +00:00
|
|
|
: 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool contains(const char* match, const char* lineEnd, const char** loc) const {
|
|
|
|
*loc = this->strnstr(match, lineEnd);
|
|
|
|
return *loc;
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
// either /n/n or /n# will stop parsing a typedef
|
2017-11-27 15:44:06 +00:00
|
|
|
const char* doubleLF() const {
|
2018-05-16 11:07:07 +00:00
|
|
|
const char* ptr = fChar - 1;
|
2017-11-27 15:44:06 +00:00
|
|
|
const char* doubleStart = nullptr;
|
2018-05-16 11:07:07 +00:00
|
|
|
while (++ptr < fEnd) {
|
|
|
|
if (!doubleStart) {
|
|
|
|
if ('\n' == ptr[0]) {
|
2017-11-27 15:44:06 +00:00
|
|
|
doubleStart = ptr;
|
|
|
|
}
|
2018-05-16 11:07:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ('\n' == ptr[0] || '#' == ptr[0]) {
|
|
|
|
return doubleStart;
|
|
|
|
}
|
|
|
|
if (' ' < ptr[0]) {
|
|
|
|
doubleStart = nullptr;
|
2017-11-27 15:44:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool endsWith(const char* match) {
|
|
|
|
int matchLen = strlen(match);
|
|
|
|
if (matchLen > fChar - fLine) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !strncmp(fChar - matchLen, match, matchLen);
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
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* );
|
|
|
|
|
2017-10-09 19:45:33 +00:00
|
|
|
char next() {
|
2017-07-28 15:04:54 +00:00
|
|
|
SkASSERT(fChar < fEnd);
|
|
|
|
char result = *fChar++;
|
|
|
|
if ('\n' == result) {
|
|
|
|
++fLineCount;
|
|
|
|
fLine = fChar;
|
|
|
|
}
|
2017-10-09 19:45:33 +00:00
|
|
|
return result;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2018-02-06 14:41:53 +00:00
|
|
|
static string ReportFilename(string file);
|
2017-07-28 15:04:54 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
void setForErrorReporting(const Definition* , const char* );
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void skipToAlphaNum() {
|
|
|
|
while (fChar < fEnd && !isalnum(fChar[0])) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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() {
|
|
|
|
while (fChar < fEnd && (isalnum(fChar[0])
|
2017-11-27 15:44:06 +00:00
|
|
|
|| '_' == fChar[0] /* || '-' == fChar[0] */
|
2017-07-28 15:04:54 +00:00
|
|
|
|| (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]))) {
|
|
|
|
if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool skipToLineStart() {
|
|
|
|
if (!this->skipLine()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!this->eof()) {
|
|
|
|
return this->skipWhiteSpace();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
void skipLower() {
|
|
|
|
while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
void skipToNonAlphaNum() {
|
2018-04-16 12:37:38 +00:00
|
|
|
while (fChar < fEnd && (isalnum(fChar[0]) || '_' == fChar[0])) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void skipToNonName() {
|
2017-07-28 15:04:54 +00:00
|
|
|
while (fChar < fEnd && (isalnum(fChar[0])
|
|
|
|
|| '_' == fChar[0] || '-' == fChar[0]
|
2017-09-01 19:51:02 +00:00
|
|
|
|| (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
|
2017-07-28 15:04:54 +00:00
|
|
|
|| ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
|
|
|
|
if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
void skipPhraseName() {
|
|
|
|
while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
void skipToSpace() {
|
|
|
|
while (fChar < fEnd && ' ' != fChar[0]) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-27 15:44:06 +00:00
|
|
|
void skipToWhiteSpace() {
|
|
|
|
while (fChar < fEnd && ' ' < fChar[0]) {
|
|
|
|
fChar++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
bool skipName(const char* word) {
|
|
|
|
size_t len = strlen(word);
|
2017-09-01 19:51:02 +00:00
|
|
|
if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
|
2017-09-14 15:25:39 +00:00
|
|
|
for (size_t i = 0; i < len; ++i) {
|
|
|
|
this->next();
|
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
return this->eof() || ' ' >= fChar[0];
|
|
|
|
}
|
|
|
|
|
2017-10-09 19:45:33 +00:00
|
|
|
bool skipSpace() {
|
|
|
|
while (' ' == this->peek()) {
|
2017-07-28 15:04:54 +00:00
|
|
|
(void) this->next();
|
|
|
|
if (fChar >= fEnd) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-10-09 19:45:33 +00:00
|
|
|
}
|
|
|
|
return true;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-09 19:45:33 +00:00
|
|
|
bool skipWhiteSpace() {
|
|
|
|
while (' ' >= this->peek()) {
|
2017-07-28 15:04:54 +00:00
|
|
|
(void) this->next();
|
|
|
|
if (fChar >= fEnd) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-10-09 19:45:33 +00:00
|
|
|
}
|
|
|
|
return true;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool startsWith(const char* str) const {
|
|
|
|
size_t len = strlen(str);
|
2017-10-09 19:45:33 +00:00
|
|
|
ptrdiff_t lineLen = fEnd - fChar;
|
2017-07-28 15:04:54 +00:00
|
|
|
return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
|
|
|
|
}
|
|
|
|
|
2017-08-03 21:14:08 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-09-01 19:51:02 +00:00
|
|
|
const char* trimmedBracketEnd(const char bracket) const {
|
|
|
|
int max = (int) (this->lineLength());
|
2017-07-28 15:04:54 +00:00
|
|
|
int index = 0;
|
|
|
|
while (index < max && bracket != fChar[index]) {
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
SkASSERT(index < max);
|
|
|
|
while (index > 0 && ' ' >= fChar[index - 1]) {
|
|
|
|
--index;
|
|
|
|
}
|
|
|
|
return fChar + index;
|
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
// FIXME: nothing else in TextParser knows from C++ --
|
|
|
|
// there could be a class between TextParser and ParserCommon
|
|
|
|
virtual string typedefName();
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
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') ||
|
2017-11-27 15:44:06 +00:00
|
|
|
(reader[0] >= 'A' && reader[0] <= 'F') ||
|
|
|
|
(reader[0] >= 'a' && reader[0] <= 'f'));
|
2017-07-28 15:04:54 +00:00
|
|
|
int nibble = *reader++ - '0';
|
|
|
|
if (nibble > 9) {
|
2017-11-27 15:44:06 +00:00
|
|
|
nibble = (nibble & ~('a' - 'A')) - 'A' + '9' + 1;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
unicode |= nibble;
|
|
|
|
}
|
|
|
|
SkASSERT(unicode < 256);
|
|
|
|
*writer++ = (unsigned char) unicode;
|
|
|
|
} else {
|
|
|
|
SkASSERT(ctrl == 'n');
|
|
|
|
*writer++ = '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fStart = fLine = fChar = fStorage;
|
|
|
|
fEnd = writer;
|
|
|
|
}
|
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
~EscapeParser() override {
|
2017-07-28 15:04:54 +00:00
|
|
|
delete fStorage;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
char* fStorage;
|
|
|
|
};
|
|
|
|
|
|
|
|
class RootDefinition;
|
|
|
|
|
|
|
|
class Definition : public NonAssignable {
|
|
|
|
public:
|
|
|
|
enum Type {
|
|
|
|
kNone,
|
|
|
|
kWord,
|
|
|
|
kMark,
|
|
|
|
kKeyWord,
|
|
|
|
kBracket,
|
|
|
|
kPunctuation,
|
|
|
|
kFileType,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class MethodType {
|
|
|
|
kNone,
|
|
|
|
kConstructor,
|
|
|
|
kDestructor,
|
|
|
|
kOperator,
|
|
|
|
};
|
|
|
|
|
2017-11-27 15:44:06 +00:00
|
|
|
enum class Operator {
|
|
|
|
kUnknown,
|
|
|
|
kAdd,
|
|
|
|
kAddTo,
|
|
|
|
kArray,
|
|
|
|
kCast,
|
|
|
|
kCopy,
|
|
|
|
kDelete,
|
|
|
|
kDereference,
|
|
|
|
kEqual,
|
|
|
|
kMinus,
|
|
|
|
kMove,
|
|
|
|
kMultiply,
|
|
|
|
kMultiplyBy,
|
|
|
|
kNew,
|
|
|
|
kNotEqual,
|
|
|
|
kSubtract,
|
|
|
|
kSubtractFrom,
|
|
|
|
};
|
|
|
|
|
2018-02-07 12:27:09 +00:00
|
|
|
enum class Format {
|
|
|
|
kIncludeReturn,
|
|
|
|
kOmitReturn,
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
enum class Details {
|
|
|
|
kNone,
|
|
|
|
kSoonToBe_Deprecated,
|
|
|
|
kTestingOnly_Experiment,
|
2018-05-30 13:21:49 +00:00
|
|
|
kDoNotUse_Experiment,
|
2018-05-16 11:07:07 +00:00
|
|
|
kNotReady_Experiment,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class DetailsType {
|
|
|
|
kPhrase,
|
|
|
|
kSentence,
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition() {}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition(const char* start, const char* end, int line, Definition* parent, char mc)
|
2017-07-28 15:04:54 +00:00
|
|
|
: fStart(start)
|
|
|
|
, fContentStart(start)
|
|
|
|
, fContentEnd(end)
|
|
|
|
, fParent(parent)
|
|
|
|
, fLineCount(line)
|
2018-03-05 18:26:16 +00:00
|
|
|
, fType(Type::kWord)
|
|
|
|
, fMC(mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
if (parent) {
|
|
|
|
SkASSERT(parent->fFileName.length() > 0);
|
|
|
|
fFileName = parent->fFileName;
|
|
|
|
}
|
|
|
|
this->setParentIndex();
|
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition(MarkType markType, const char* start, int line, Definition* parent, char mc)
|
|
|
|
: Definition(markType, start, nullptr, line, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent, char mc)
|
|
|
|
: Definition(start, end, line, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
fMarkType = markType;
|
2017-10-09 19:45:33 +00:00
|
|
|
fType = Type::kMark;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition(Bracket bracket, const char* start, int lineCount, Definition* parent, char mc)
|
|
|
|
: Definition(start, nullptr, lineCount, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
fBracket = bracket;
|
|
|
|
fType = Type::kBracket;
|
|
|
|
}
|
|
|
|
|
2017-10-09 19:45:33 +00:00
|
|
|
Definition(KeyWord keyWord, const char* start, const char* end, int lineCount,
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition* parent, char mc)
|
|
|
|
: Definition(start, end, lineCount, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
fKeyWord = keyWord;
|
|
|
|
fType = Type::kKeyWord;
|
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent, char mc)
|
|
|
|
: Definition(start, nullptr, lineCount, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
fPunctuation = punctuation;
|
|
|
|
fType = Type::kPunctuation;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~Definition() {}
|
|
|
|
|
|
|
|
virtual RootDefinition* asRoot() { SkASSERT(0); return nullptr; }
|
2018-04-16 12:37:38 +00:00
|
|
|
bool boilerplateIfDef();
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
bool boilerplateEndIf() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkMethod() const;
|
2017-08-29 21:36:51 +00:00
|
|
|
bool crossCheck2(const Definition& includeToken) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool crossCheck(const Definition& includeToken) const;
|
|
|
|
bool crossCheckInside(const char* start, const char* end, const Definition& includeToken) const;
|
2018-02-01 14:37:32 +00:00
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
Definition* csParent() {
|
2018-02-01 14:37:32 +00:00
|
|
|
Definition* test = fParent;
|
|
|
|
while (test) {
|
|
|
|
if (MarkType::kStruct == test->fMarkType || MarkType::kClass == test->fMarkType) {
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
test = test->fParent;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
string fiddleName() const;
|
2018-04-16 12:37:38 +00:00
|
|
|
string fileName() const;
|
2018-02-06 14:41:53 +00:00
|
|
|
const Definition* findClone(string match) const;
|
2018-02-07 12:27:09 +00:00
|
|
|
string formatFunction(Format format) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
const Definition* hasChild(MarkType markType) const;
|
2018-04-16 12:37:38 +00:00
|
|
|
bool hasMatch(string name) const;
|
|
|
|
const Definition* hasParam(string ref) const;
|
2018-05-16 11:07:07 +00:00
|
|
|
string incompleteMessage(DetailsType ) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool isClone() const { return fClone; }
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* iRootParent() const {
|
|
|
|
const Definition* test = fParent;
|
2017-07-28 15:04:54 +00:00
|
|
|
while (test) {
|
2018-06-27 15:00:21 +00:00
|
|
|
if (KeyWord::kClass == test->fKeyWord || KeyWord::kStruct == test->fKeyWord) {
|
2017-07-28 15:04:54 +00:00
|
|
|
return test;
|
|
|
|
}
|
|
|
|
test = test->fParent;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isRoot() const { return false; }
|
2018-02-01 14:37:32 +00:00
|
|
|
bool isStructOrClass() const;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
int length() const {
|
|
|
|
return (int) (fContentEnd - fContentStart);
|
|
|
|
}
|
|
|
|
|
2018-07-12 20:24:53 +00:00
|
|
|
const char* methodEnd() const;
|
2018-04-16 12:37:38 +00:00
|
|
|
bool methodHasReturn(string name, TextParser* methodParser) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
string methodName() const;
|
2017-10-09 19:45:33 +00:00
|
|
|
bool nextMethodParam(TextParser* methodParser, const char** nextEndPtr,
|
2017-07-28 15:04:54 +00:00
|
|
|
string* paramName) const;
|
2017-11-27 15:44:06 +00:00
|
|
|
static string NormalizedName(string name);
|
2018-04-16 12:37:38 +00:00
|
|
|
bool paramsMatch(string fullRef, string name) const;
|
2017-11-27 15:44:06 +00:00
|
|
|
bool parseOperator(size_t doubleColons, string& result);
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
string printableName() const {
|
|
|
|
string result(fName);
|
|
|
|
std::replace(result.begin(), result.end(), '_', ' ');
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-09-19 21:39:32 +00:00
|
|
|
template <typename T> T reportError(const char* errorStr) const {
|
|
|
|
TextParser tp(this);
|
|
|
|
tp.reportError(errorStr);
|
|
|
|
return T();
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
virtual RootDefinition* rootParent() { SkASSERT(0); return nullptr; }
|
2018-01-30 15:08:57 +00:00
|
|
|
virtual const RootDefinition* rootParent() const { SkASSERT(0); return nullptr; }
|
2017-11-27 15:44:06 +00:00
|
|
|
void setCanonicalFiddle();
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
void setParentIndex() {
|
|
|
|
fParentIndex = fParent ? (int) fParent->fTokens.size() : -1;
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* subtopicParent() const {
|
|
|
|
Definition* test = fParent;
|
|
|
|
while (test) {
|
|
|
|
if (MarkType::kTopic == test->fMarkType || MarkType::kSubtopic == test->fMarkType) {
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
test = test->fParent;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-02-09 21:49:09 +00:00
|
|
|
const Definition* topicParent() const {
|
|
|
|
Definition* test = fParent;
|
|
|
|
while (test) {
|
|
|
|
if (MarkType::kTopic == test->fMarkType) {
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
test = test->fParent;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
string fText; // if text is constructed instead of in a file, it's put here
|
|
|
|
const char* fStart = nullptr; // .. in original text file, or the start of fText
|
|
|
|
const char* fContentStart; // start past optional markup name
|
|
|
|
string fName;
|
|
|
|
string fFiddle; // if its a constructor or operator, fiddle name goes here
|
|
|
|
const char* fContentEnd = nullptr; // the end of the contained text
|
|
|
|
const char* fTerminator = nullptr; // the end of the markup, normally ##\n or \n
|
|
|
|
Definition* fParent = nullptr;
|
|
|
|
list<Definition> fTokens;
|
|
|
|
vector<Definition*> fChildren;
|
|
|
|
string fHash; // generated by fiddle
|
|
|
|
string fFileName;
|
2017-11-27 15:44:06 +00:00
|
|
|
mutable string fWrapper; // used by Example to wrap into proper function
|
2017-07-28 15:04:54 +00:00
|
|
|
size_t fLineCount = 0;
|
|
|
|
int fParentIndex = 0;
|
|
|
|
MarkType fMarkType = MarkType::kNone;
|
|
|
|
KeyWord fKeyWord = KeyWord::kNone;
|
|
|
|
Bracket fBracket = Bracket::kNone;
|
|
|
|
Punctuation fPunctuation = Punctuation::kNone;
|
|
|
|
MethodType fMethodType = MethodType::kNone;
|
2017-11-27 15:44:06 +00:00
|
|
|
Operator fOperator = Operator::kUnknown;
|
2017-07-28 15:04:54 +00:00
|
|
|
Type fType = Type::kNone;
|
2018-03-05 18:26:16 +00:00
|
|
|
char fMC = '#';
|
2017-07-28 15:04:54 +00:00
|
|
|
bool fClone = false;
|
|
|
|
bool fCloned = false;
|
2018-02-06 14:41:53 +00:00
|
|
|
bool fDeprecated = false;
|
2017-11-27 15:44:06 +00:00
|
|
|
bool fOperatorConst = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool fPrivate = false;
|
2018-05-16 11:07:07 +00:00
|
|
|
Details fDetails = Details::kNone;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool fMemberStart = false;
|
2017-09-14 15:25:39 +00:00
|
|
|
bool fAnonymous = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
mutable bool fVisited = false;
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
class SubtopicKeys {
|
|
|
|
public:
|
|
|
|
static constexpr const char* kClasses = "Class";
|
|
|
|
static constexpr const char* kConstants = "Constant";
|
|
|
|
static constexpr const char* kConstructors = "Constructor";
|
|
|
|
static constexpr const char* kDefines = "Define";
|
|
|
|
static constexpr const char* kMemberFunctions = "Member_Function";
|
|
|
|
static constexpr const char* kMembers = "Member";
|
|
|
|
static constexpr const char* kOperators = "Operator";
|
|
|
|
static constexpr const char* kOverview = "Overview";
|
|
|
|
static constexpr const char* kRelatedFunctions = "Related_Function";
|
|
|
|
static constexpr const char* kStructs = "Struct";
|
|
|
|
static constexpr const char* kTypedefs = "Typedef";
|
|
|
|
|
|
|
|
static const char* kGeneratedSubtopics[];
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
class RootDefinition : public Definition {
|
|
|
|
public:
|
2017-09-01 19:51:02 +00:00
|
|
|
enum class AllowParens {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
struct SubtopicContents {
|
|
|
|
SubtopicContents()
|
|
|
|
: fShowClones(false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<Definition*> fMembers;
|
|
|
|
bool fShowClones;
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
RootDefinition() {
|
|
|
|
}
|
2017-10-09 19:45:33 +00:00
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
RootDefinition(MarkType markType, const char* start, int line, Definition* parent, char mc)
|
|
|
|
: Definition(markType, start, line, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 19:45:33 +00:00
|
|
|
RootDefinition(MarkType markType, const char* start, const char* end, int line,
|
2018-03-05 18:26:16 +00:00
|
|
|
Definition* parent, char mc) : Definition(markType, start, end, line, parent, mc) {
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~RootDefinition() override {
|
|
|
|
for (auto& iter : fBranches) {
|
|
|
|
delete iter.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RootDefinition* asRoot() override { return this; }
|
|
|
|
void clearVisited();
|
2018-01-05 17:10:09 +00:00
|
|
|
bool dumpUnVisited();
|
2018-05-16 11:07:07 +00:00
|
|
|
Definition* find(string ref, AllowParens );
|
2017-07-28 15:04:54 +00:00
|
|
|
bool isRoot() const override { return true; }
|
2018-05-16 11:07:07 +00:00
|
|
|
|
|
|
|
SubtopicContents& populator(const char* key) {
|
|
|
|
return fPopulators[key];
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
RootDefinition* rootParent() override { return fRootParent; }
|
2018-01-30 15:08:57 +00:00
|
|
|
const RootDefinition* rootParent() const override { return fRootParent; }
|
2017-07-28 15:04:54 +00:00
|
|
|
void setRootParent(RootDefinition* rootParent) { fRootParent = rootParent; }
|
|
|
|
|
|
|
|
unordered_map<string, RootDefinition*> fBranches;
|
|
|
|
unordered_map<string, Definition> fLeaves;
|
2018-05-16 11:07:07 +00:00
|
|
|
unordered_map<string, SubtopicContents> fPopulators;
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
|
|
|
RootDefinition* fRootParent = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct IClassDefinition : public Definition {
|
2018-04-26 12:32:37 +00:00
|
|
|
unordered_map<string, Definition*> fConsts;
|
2018-04-16 12:37:38 +00:00
|
|
|
unordered_map<string, Definition*> fDefines;
|
2017-07-28 15:04:54 +00:00
|
|
|
unordered_map<string, Definition*> fEnums;
|
|
|
|
unordered_map<string, Definition*> fMembers;
|
|
|
|
unordered_map<string, Definition*> fMethods;
|
|
|
|
unordered_map<string, Definition*> fStructs;
|
2017-12-11 21:03:17 +00:00
|
|
|
unordered_map<string, Definition*> fTypedefs;
|
2017-07-28 15:04:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Reference {
|
|
|
|
Reference()
|
|
|
|
: fLocation(nullptr)
|
|
|
|
, fDefinition(nullptr) {
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* fLocation; // .. in original text file
|
|
|
|
const Definition* fDefinition;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TypeNames {
|
|
|
|
const char* fName;
|
|
|
|
MarkType fMarkType;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ParserCommon : public TextParser {
|
|
|
|
public:
|
2018-04-03 12:43:27 +00:00
|
|
|
enum class OneFile {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2018-05-30 13:21:49 +00:00
|
|
|
enum class OneLine {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
|
|
|
|
2018-06-07 13:59:07 +00:00
|
|
|
enum class IndentKind {
|
|
|
|
kConstOut,
|
|
|
|
kEnumChild,
|
|
|
|
kEnumChild2,
|
|
|
|
kEnumHeader,
|
|
|
|
kEnumHeader2,
|
|
|
|
kMethodOut,
|
|
|
|
kStructMember,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct IndentState {
|
|
|
|
IndentState(IndentKind kind, int indent)
|
|
|
|
: fKind(kind)
|
|
|
|
, fIndent(indent) {
|
|
|
|
}
|
|
|
|
|
|
|
|
IndentKind fKind;
|
|
|
|
int fIndent;
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
ParserCommon() : TextParser()
|
|
|
|
, fParent(nullptr)
|
2017-09-14 15:25:39 +00:00
|
|
|
, fDebugOut(false)
|
2018-05-16 11:07:07 +00:00
|
|
|
, fValidate(false)
|
2018-06-07 13:59:07 +00:00
|
|
|
, fReturnOnWrite(false)
|
2017-07-28 15:04:54 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
~ParserCommon() override {
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void addDefinition(Definition* def) {
|
|
|
|
fParent->fChildren.push_back(def);
|
|
|
|
fParent = def;
|
|
|
|
}
|
|
|
|
|
2018-06-08 19:57:37 +00:00
|
|
|
char* FindDateTime(char* buffer, int size);
|
|
|
|
|
2018-06-07 13:59:07 +00:00
|
|
|
void indentIn(IndentKind kind) {
|
|
|
|
fIndent += 4;
|
|
|
|
fIndentStack.emplace_back(kind, fIndent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void indentOut() {
|
|
|
|
SkASSERT(fIndent >= 4);
|
|
|
|
SkASSERT(fIndentStack.back().fIndent == fIndent);
|
|
|
|
fIndent -= 4;
|
|
|
|
fIndentStack.pop_back();
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
void indentToColumn(int column) {
|
|
|
|
SkASSERT(column >= fColumn);
|
2018-06-07 13:59:07 +00:00
|
|
|
SkASSERT(!fReturnOnWrite);
|
2017-09-14 15:25:39 +00:00
|
|
|
if (fDebugOut) {
|
|
|
|
SkDebugf("%*s", column - fColumn, "");
|
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
fprintf(fOut, "%*s", column - fColumn, "");
|
|
|
|
fColumn = column;
|
|
|
|
fSpaces += column - fColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool leadingPunctuation(const char* str, size_t len) const {
|
|
|
|
if (!fPendingSpace) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (len < 2) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ('.' != str[0] && ',' != str[0] && ';' != str[0] && ':' != str[0]) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ' ' >= str[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void lf(int count) {
|
|
|
|
fPendingLF = SkTMax(fPendingLF, count);
|
|
|
|
this->nl();
|
|
|
|
}
|
|
|
|
|
|
|
|
void lfAlways(int count) {
|
|
|
|
this->lf(count);
|
|
|
|
this->writePending();
|
|
|
|
}
|
|
|
|
|
|
|
|
void lfcr() {
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void nl() {
|
2018-06-07 13:59:07 +00:00
|
|
|
SkASSERT(!fReturnOnWrite);
|
2017-07-28 15:04:54 +00:00
|
|
|
fLinefeeds = 0;
|
|
|
|
fSpaces = 0;
|
|
|
|
fColumn = 0;
|
2017-09-19 21:39:32 +00:00
|
|
|
fPendingSpace = 0;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
bool parseFile(const char* file, const char* suffix, OneFile );
|
2017-12-11 21:03:17 +00:00
|
|
|
bool parseStatus(const char* file, const char* suffix, StatusFilter filter);
|
2017-07-28 15:04:54 +00:00
|
|
|
virtual bool parseFromFile(const char* path) = 0;
|
|
|
|
bool parseSetup(const char* path);
|
|
|
|
|
|
|
|
void popObject() {
|
|
|
|
fParent->fContentEnd = fParent->fTerminator = fChar;
|
|
|
|
fParent = fParent->fParent;
|
|
|
|
}
|
|
|
|
|
2018-06-08 19:57:37 +00:00
|
|
|
char* ReadToBuffer(string filename, int* size);
|
2018-01-04 21:11:51 +00:00
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
virtual void reset() = 0;
|
|
|
|
|
|
|
|
void resetCommon() {
|
|
|
|
fLine = fChar = fStart;
|
|
|
|
fLineCount = 0;
|
|
|
|
fParent = nullptr;
|
|
|
|
fIndent = 0;
|
|
|
|
fOut = nullptr;
|
|
|
|
fMaxLF = 2;
|
|
|
|
fPendingLF = 0;
|
2017-09-19 21:39:32 +00:00
|
|
|
fPendingSpace = 0;
|
2017-10-26 11:58:48 +00:00
|
|
|
fOutdentNext = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
nl();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setAsParent(Definition* definition) {
|
|
|
|
if (fParent) {
|
|
|
|
fParent->fChildren.push_back(definition);
|
|
|
|
definition->fParent = fParent;
|
|
|
|
}
|
|
|
|
fParent = definition;
|
|
|
|
}
|
|
|
|
|
|
|
|
void singleLF() {
|
|
|
|
fMaxLF = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeBlock(int size, const char* data) {
|
|
|
|
SkAssertResult(writeBlockTrim(size, data));
|
|
|
|
}
|
2017-10-26 11:58:48 +00:00
|
|
|
|
2018-05-30 13:21:49 +00:00
|
|
|
bool writeBlockIndent(int size, const char* data);
|
2018-04-16 12:37:38 +00:00
|
|
|
|
|
|
|
void writeBlockSeparator() {
|
|
|
|
this->writeString(
|
|
|
|
"# ------------------------------------------------------------------------------");
|
|
|
|
this->lf(2);
|
|
|
|
}
|
|
|
|
|
2017-10-26 11:58:48 +00:00
|
|
|
bool writeBlockTrim(int size, const char* data);
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
void writeCommentHeader() {
|
|
|
|
this->lf(2);
|
|
|
|
this->writeString("/**");
|
|
|
|
this->writeSpace();
|
|
|
|
}
|
|
|
|
|
2018-05-30 13:21:49 +00:00
|
|
|
void writeCommentTrailer(OneLine oneLine) {
|
|
|
|
if (OneLine::kNo == oneLine) {
|
|
|
|
this->lf(1);
|
|
|
|
} else {
|
|
|
|
this->writeSpace();
|
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
this->writeString("*/");
|
|
|
|
this->lfcr();
|
|
|
|
}
|
|
|
|
|
2017-10-26 11:58:48 +00:00
|
|
|
void writePending();
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
// write a pending space, so that two consecutive calls
|
|
|
|
// don't double write, and trailing spaces on lines aren't written
|
2017-09-19 21:39:32 +00:00
|
|
|
void writeSpace(int count = 1) {
|
2018-06-07 13:59:07 +00:00
|
|
|
SkASSERT(!fReturnOnWrite);
|
2017-07-28 15:04:54 +00:00
|
|
|
SkASSERT(!fPendingLF);
|
|
|
|
SkASSERT(!fLinefeeds);
|
|
|
|
SkASSERT(fColumn > 0);
|
|
|
|
SkASSERT(!fSpaces);
|
2017-09-19 21:39:32 +00:00
|
|
|
fPendingSpace = count;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2017-10-26 11:58:48 +00:00
|
|
|
void writeString(const char* str);
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeString(string str) {
|
2017-09-19 21:39:32 +00:00
|
|
|
this->writeString(str.c_str());
|
|
|
|
}
|
|
|
|
|
2018-01-04 21:11:51 +00:00
|
|
|
bool writtenFileDiffers(string filename, string readname);
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
unordered_map<string, sk_sp<SkData>> fRawData;
|
|
|
|
unordered_map<string, vector<char>> fLFOnly;
|
2018-06-07 13:59:07 +00:00
|
|
|
vector<IndentState> fIndentStack;
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition* fParent;
|
|
|
|
FILE* fOut;
|
|
|
|
int fLinefeeds; // number of linefeeds last written, zeroed on non-space
|
2017-09-19 21:39:32 +00:00
|
|
|
int fMaxLF; // number of linefeeds allowed
|
|
|
|
int fPendingLF; // number of linefeeds to write (can be suppressed)
|
|
|
|
int fSpaces; // number of spaces (indent) last written, zeroed on non-space
|
|
|
|
int fColumn; // current column; number of chars past last linefeed
|
|
|
|
int fIndent; // desired indention
|
|
|
|
int fPendingSpace; // one or two spaces should preceed the next string or block
|
|
|
|
char fLastChar; // last written
|
|
|
|
bool fDebugOut; // set true to write to std out
|
2018-05-16 11:07:07 +00:00
|
|
|
bool fValidate; // set true to check anchor defs and refs
|
2017-10-26 11:58:48 +00:00
|
|
|
bool fOutdentNext; // set at end of embedded struct to prevent premature outdent
|
2018-05-16 11:07:07 +00:00
|
|
|
bool fWroteSomething; // used to detect empty content; an alternative source is preferable
|
2018-06-07 13:59:07 +00:00
|
|
|
bool fReturnOnWrite; // used to detect non-empty content; allowing early return
|
2018-05-16 11:07:07 +00:00
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
|
|
|
typedef TextParser INHERITED;
|
|
|
|
};
|
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
struct JsonStatus {
|
|
|
|
const Json::Value& fObject;
|
|
|
|
Json::Value::iterator fIter;
|
|
|
|
string fName;
|
|
|
|
};
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
class StatusIter : public ParserCommon {
|
|
|
|
public:
|
|
|
|
StatusIter(const char* statusFile, const char* suffix, StatusFilter);
|
|
|
|
~StatusIter() override {}
|
|
|
|
string baseDir();
|
|
|
|
bool empty() { return fStack.empty(); }
|
|
|
|
bool next(string* file);
|
|
|
|
protected:
|
|
|
|
bool parseFromFile(const char* path) override;
|
|
|
|
void reset() override;
|
|
|
|
private:
|
|
|
|
vector<JsonStatus> fStack;
|
|
|
|
Json::Value fRoot;
|
|
|
|
const char* fSuffix;
|
|
|
|
StatusFilter fFilter;
|
|
|
|
};
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
class BmhParser : public ParserCommon {
|
|
|
|
public:
|
|
|
|
enum class MarkLookup {
|
|
|
|
kRequire,
|
|
|
|
kAllowUnknown,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class Resolvable {
|
2018-02-07 12:27:09 +00:00
|
|
|
kNo, // neither resolved nor output
|
|
|
|
kYes, // resolved, output
|
2018-04-03 12:43:27 +00:00
|
|
|
kOut, // mostly resolved, output (FIXME: is this really different from kYes?)
|
|
|
|
kFormula, // resolve methods as they are used, not as they are prototyped
|
|
|
|
kLiteral, // output untouched
|
2018-02-07 12:27:09 +00:00
|
|
|
kClone, // resolved, output, with references to clones as well
|
2018-05-16 11:07:07 +00:00
|
|
|
kSimple, // resolve simple words (used to resolve method declarations)
|
2017-07-28 15:04:54 +00:00
|
|
|
};
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
enum class ExampleOptions {
|
|
|
|
kText,
|
|
|
|
kPng,
|
|
|
|
kAll
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
enum class Exemplary {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
kOptional,
|
|
|
|
};
|
|
|
|
|
2017-09-01 19:51:02 +00:00
|
|
|
enum class TableState {
|
|
|
|
kNone,
|
|
|
|
kColumnStart,
|
|
|
|
kColumnEnd,
|
|
|
|
};
|
|
|
|
|
2018-02-27 14:54:21 +00:00
|
|
|
enum class HasTag {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
enum class TrimExtract {
|
|
|
|
kNo,
|
|
|
|
kYes
|
|
|
|
};
|
|
|
|
|
2017-11-27 15:44:06 +00:00
|
|
|
BmhParser(bool skip) : ParserCommon()
|
2017-10-09 19:45:33 +00:00
|
|
|
, fMaps {
|
2018-06-07 13:59:07 +00:00
|
|
|
{ &fClassMap, MarkType::kClass }
|
2018-04-16 12:37:38 +00:00
|
|
|
, { &fConstMap, MarkType::kConst }
|
|
|
|
, { &fDefineMap, MarkType::kDefine }
|
|
|
|
, { &fEnumMap, MarkType::kEnum }
|
|
|
|
, { &fClassMap, MarkType::kEnumClass }
|
|
|
|
, { &fMethodMap, MarkType::kMethod }
|
|
|
|
, { &fClassMap, MarkType::kStruct }
|
|
|
|
, { &fTypedefMap, MarkType::kTypedef }
|
|
|
|
}
|
|
|
|
, fSkip(skip) {
|
2017-07-28 15:04:54 +00:00
|
|
|
this->reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
~BmhParser() override {}
|
|
|
|
|
|
|
|
bool addDefinition(const char* defStart, bool hasEnd, MarkType markType,
|
2018-02-27 14:54:21 +00:00
|
|
|
const vector<string>& typeNameBuilder, HasTag hasTag);
|
|
|
|
bool checkEndMarker(MarkType markType, string name) const;
|
2017-08-29 21:36:51 +00:00
|
|
|
bool checkExamples() const;
|
2018-03-05 18:26:16 +00:00
|
|
|
const char* checkForFullTerminal(const char* end, const Definition* ) const;
|
2017-08-30 12:58:10 +00:00
|
|
|
bool checkParamReturn(const Definition* definition) const;
|
2018-03-05 18:26:16 +00:00
|
|
|
bool dumpExamples(FILE* fiddleOut, Definition& def, bool* continuation) const;
|
2017-08-29 21:36:51 +00:00
|
|
|
bool dumpExamples(const char* fiddleJsonFileName) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool childOf(MarkType markType) const;
|
|
|
|
string className(MarkType markType);
|
|
|
|
bool collectExternals();
|
|
|
|
int endHashCount() const;
|
2017-09-01 19:51:02 +00:00
|
|
|
bool endTableColumn(const char* end, const char* terminator);
|
2018-03-05 18:26:16 +00:00
|
|
|
bool exampleToScript(Definition*, ExampleOptions, string* result ) const;
|
|
|
|
string extractText(const Definition* , TrimExtract ) const;
|
2018-06-07 13:59:07 +00:00
|
|
|
RootDefinition* findBmhObject(MarkType markType, string typeName);
|
2017-07-28 15:04:54 +00:00
|
|
|
bool findDefinitions();
|
2018-02-27 14:54:21 +00:00
|
|
|
Definition* findExample(string name) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
MarkType getMarkType(MarkLookup lookup) const;
|
|
|
|
bool hasEndToken() const;
|
|
|
|
string memberName();
|
|
|
|
string methodName();
|
|
|
|
const Definition* parentSpace() const;
|
|
|
|
|
|
|
|
bool parseFromFile(const char* path) override {
|
|
|
|
if (!INHERITED::parseSetup(path)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
fCheckMethods = !strstr(path, "undocumented.bmh");
|
|
|
|
return findDefinitions();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool popParentStack(Definition* definition);
|
2018-04-16 12:37:38 +00:00
|
|
|
void reportDuplicates(const Definition& def, string dup) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
void reset() override {
|
|
|
|
INHERITED::resetCommon();
|
|
|
|
fRoot = nullptr;
|
2017-09-01 19:51:02 +00:00
|
|
|
fWorkingColumn = nullptr;
|
|
|
|
fRow = nullptr;
|
|
|
|
fTableState = TableState::kNone;
|
2017-07-28 15:04:54 +00:00
|
|
|
fMC = '#';
|
|
|
|
fInChar = false;
|
|
|
|
fInCharCommentString = false;
|
|
|
|
fInComment = false;
|
|
|
|
fInEnum = false;
|
|
|
|
fInString = false;
|
|
|
|
fCheckMethods = false;
|
|
|
|
}
|
|
|
|
|
2018-03-05 18:26:16 +00:00
|
|
|
void setWrapper(Definition* def) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool skipNoName();
|
|
|
|
bool skipToDefinitionEnd(MarkType markType);
|
2018-01-30 15:08:57 +00:00
|
|
|
bool skipToString();
|
2017-09-01 19:51:02 +00:00
|
|
|
void spellCheck(const char* match, SkCommandLineFlags::StringArray report) const;
|
2017-12-11 21:03:17 +00:00
|
|
|
void spellStatus(const char* match, SkCommandLineFlags::StringArray report) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
vector<string> topicName();
|
|
|
|
vector<string> typeName(MarkType markType, bool* expectEnd);
|
2017-12-11 21:03:17 +00:00
|
|
|
string typedefName() override;
|
2018-04-16 12:37:38 +00:00
|
|
|
string uniqueName(string base, MarkType markType);
|
|
|
|
string uniqueRootName(string base, MarkType markType);
|
2017-07-28 15:04:54 +00:00
|
|
|
void validate() const;
|
2018-04-16 12:37:38 +00:00
|
|
|
string word(string prefix, string delimiter);
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
public:
|
2018-04-16 12:37:38 +00:00
|
|
|
struct MarkProps {
|
2017-07-28 15:04:54 +00:00
|
|
|
const char* fName;
|
|
|
|
MarkType fMarkType;
|
|
|
|
Resolvable fResolve;
|
|
|
|
Exemplary fExemplary; // worthy of an example
|
|
|
|
uint64_t fParentMask;
|
|
|
|
};
|
2017-10-09 19:45:33 +00:00
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
struct DefinitionMap {
|
|
|
|
unordered_map<string, RootDefinition>* fMap;
|
|
|
|
MarkType fMarkType;
|
|
|
|
};
|
|
|
|
|
2018-06-07 13:59:07 +00:00
|
|
|
vector<DefinitionMap> fMaps;
|
2018-04-16 12:37:38 +00:00
|
|
|
|
|
|
|
static MarkProps kMarkProps[Last_MarkType + 1];
|
2017-07-28 15:04:54 +00:00
|
|
|
forward_list<RootDefinition> fTopics;
|
|
|
|
forward_list<Definition> fMarkup;
|
|
|
|
forward_list<RootDefinition> fExternals;
|
|
|
|
vector<string> fInputFiles;
|
|
|
|
unordered_map<string, RootDefinition> fClassMap;
|
|
|
|
unordered_map<string, RootDefinition> fConstMap;
|
2018-04-16 12:37:38 +00:00
|
|
|
unordered_map<string, RootDefinition> fDefineMap;
|
2017-07-28 15:04:54 +00:00
|
|
|
unordered_map<string, RootDefinition> fEnumMap;
|
|
|
|
unordered_map<string, RootDefinition> fMethodMap;
|
|
|
|
unordered_map<string, RootDefinition> fTypedefMap;
|
|
|
|
unordered_map<string, Definition*> fTopicMap;
|
|
|
|
unordered_map<string, Definition*> fAliasMap;
|
2018-03-05 18:26:16 +00:00
|
|
|
unordered_map<string, Definition*> fPhraseMap;
|
2017-07-28 15:04:54 +00:00
|
|
|
RootDefinition* fRoot;
|
2017-09-01 19:51:02 +00:00
|
|
|
Definition* fWorkingColumn;
|
|
|
|
Definition* fRow;
|
|
|
|
const char* fColStart;
|
|
|
|
TableState fTableState;
|
2017-07-28 15:04:54 +00:00
|
|
|
mutable char fMC; // markup character
|
|
|
|
bool fAnonymous;
|
|
|
|
bool fCloned;
|
|
|
|
bool fInChar;
|
|
|
|
bool fInCharCommentString;
|
|
|
|
bool fInEnum;
|
|
|
|
bool fInComment;
|
|
|
|
bool fInString;
|
|
|
|
bool fCheckMethods;
|
2017-11-27 15:44:06 +00:00
|
|
|
bool fSkip = false;
|
2017-09-14 15:25:39 +00:00
|
|
|
bool fWroteOut = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
|
|
|
typedef ParserCommon INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IncludeParser : public ParserCommon {
|
|
|
|
public:
|
|
|
|
enum class IsStruct {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
|
|
|
|
|
|
|
IncludeParser() : ParserCommon()
|
|
|
|
, fMaps {
|
2018-06-07 13:59:07 +00:00
|
|
|
{ &fIConstMap, MarkType::kConst }
|
2017-07-28 15:04:54 +00:00
|
|
|
, { &fIDefineMap, MarkType::kDefine }
|
|
|
|
, { &fIEnumMap, MarkType::kEnum }
|
|
|
|
, { &fIEnumMap, MarkType::kEnumClass }
|
|
|
|
, { &fIStructMap, MarkType::kStruct }
|
|
|
|
, { &fITemplateMap, MarkType::kTemplate }
|
|
|
|
, { &fITypedefMap, MarkType::kTypedef }
|
|
|
|
, { &fIUnionMap, MarkType::kUnion }
|
2018-06-07 13:59:07 +00:00
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
{
|
|
|
|
this->reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
~IncludeParser() override {}
|
|
|
|
|
|
|
|
void addKeyword(KeyWord keyWord);
|
|
|
|
|
|
|
|
void addPunctuation(Punctuation punctuation) {
|
2018-03-05 18:26:16 +00:00
|
|
|
fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent, '\0');
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void addWord() {
|
2018-03-05 18:26:16 +00:00
|
|
|
fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent, '\0');
|
2017-07-28 15:04:54 +00:00
|
|
|
fIncludeWord = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkForMissingParams(const vector<string>& methodParams,
|
|
|
|
const vector<string>& foundParams);
|
|
|
|
bool checkForWord();
|
|
|
|
string className() const;
|
|
|
|
bool crossCheck(BmhParser& );
|
2018-04-16 12:37:38 +00:00
|
|
|
IClassDefinition* defineClass(const Definition& includeDef, string className);
|
2017-07-28 15:04:54 +00:00
|
|
|
void dumpClassTokens(IClassDefinition& classDef);
|
2017-09-19 21:39:32 +00:00
|
|
|
void dumpComment(const Definition& );
|
2018-04-16 12:37:38 +00:00
|
|
|
void dumpCommonTail(const Definition& );
|
2018-06-27 15:00:21 +00:00
|
|
|
void dumpConst(const Definition& , string className);
|
2018-04-16 12:37:38 +00:00
|
|
|
void dumpDefine(const Definition& );
|
|
|
|
void dumpEnum(const Definition& , string name);
|
|
|
|
bool dumpGlobals();
|
|
|
|
void dumpMethod(const Definition& , string className);
|
2017-09-19 21:39:32 +00:00
|
|
|
void dumpMember(const Definition& );
|
2018-04-16 12:37:38 +00:00
|
|
|
bool dumpTokens();
|
|
|
|
bool dumpTokens(string skClassName);
|
2017-07-28 15:04:54 +00:00
|
|
|
bool findComments(const Definition& includeDef, Definition* markupDef);
|
|
|
|
Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
|
2018-06-07 13:59:07 +00:00
|
|
|
string typeName);
|
2017-07-28 15:04:54 +00:00
|
|
|
static KeyWord FindKey(const char* start, const char* end);
|
2018-06-27 15:00:21 +00:00
|
|
|
Bracket grandParentBracket() const;
|
2018-04-16 12:37:38 +00:00
|
|
|
bool isClone(const Definition& token);
|
|
|
|
bool isConstructor(const Definition& token, string className);
|
|
|
|
bool isInternalName(const Definition& token);
|
|
|
|
bool isOperator(const Definition& token);
|
2018-06-27 15:00:21 +00:00
|
|
|
Definition* parentBracket(Definition* parent) const;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool parseChar();
|
2018-04-16 12:37:38 +00:00
|
|
|
bool parseComment(string filename, const char* start, const char* end, int lineCount,
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition* markupDef);
|
|
|
|
bool parseClass(Definition* def, IsStruct);
|
2018-04-26 12:32:37 +00:00
|
|
|
bool parseConst(Definition* child, Definition* markupDef);
|
2018-04-16 12:37:38 +00:00
|
|
|
bool parseDefine(Definition* child, Definition* markupDef);
|
2017-07-28 15:04:54 +00:00
|
|
|
bool parseEnum(Definition* child, Definition* markupDef);
|
|
|
|
|
|
|
|
bool parseFromFile(const char* path) override {
|
2017-12-11 21:03:17 +00:00
|
|
|
this->reset();
|
2017-07-28 15:04:54 +00:00
|
|
|
if (!INHERITED::parseSetup(path)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
string name(path);
|
2018-01-26 17:56:22 +00:00
|
|
|
return this->parseInclude(name);
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
bool parseInclude(string name);
|
2017-07-28 15:04:54 +00:00
|
|
|
bool parseMember(Definition* child, Definition* markupDef);
|
|
|
|
bool parseMethod(Definition* child, Definition* markupDef);
|
|
|
|
bool parseObject(Definition* child, Definition* markupDef);
|
|
|
|
bool parseObjects(Definition* parent, Definition* markupDef);
|
2018-03-09 20:32:01 +00:00
|
|
|
bool parseTemplate(Definition* child, Definition* markupDef);
|
2017-12-11 21:03:17 +00:00
|
|
|
bool parseTypedef(Definition* child, Definition* markupDef);
|
2017-07-28 15:04:54 +00:00
|
|
|
bool parseUnion();
|
|
|
|
|
|
|
|
void popBracket() {
|
2018-06-27 15:00:21 +00:00
|
|
|
if (Definition::Type::kKeyWord == fParent->fType
|
|
|
|
&& KeyWord::kTypename == fParent->fKeyWord) {
|
|
|
|
this->popObject();
|
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
SkASSERT(Definition::Type::kBracket == fParent->fType);
|
|
|
|
this->popObject();
|
|
|
|
Bracket bracket = this->topBracket();
|
|
|
|
this->setBracketShortCuts(bracket);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pushBracket(Bracket bracket) {
|
|
|
|
this->setBracketShortCuts(bracket);
|
2018-03-05 18:26:16 +00:00
|
|
|
fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent, '\0');
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition* container = &fParent->fTokens.back();
|
|
|
|
this->addDefinition(container);
|
|
|
|
}
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
bool references(const SkString& file) const;
|
|
|
|
|
2018-01-26 17:56:22 +00:00
|
|
|
static void RemoveFile(const char* docs, const char* includes);
|
|
|
|
static void RemoveOneFile(const char* docs, const char* includesFileOrPath);
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
void reset() override {
|
|
|
|
INHERITED::resetCommon();
|
|
|
|
fRootTopic = nullptr;
|
2018-06-07 13:59:07 +00:00
|
|
|
fConstExpr = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
fInBrace = nullptr;
|
|
|
|
fIncludeWord = nullptr;
|
2017-08-29 21:36:51 +00:00
|
|
|
fLastObject = nullptr;
|
2018-06-07 13:59:07 +00:00
|
|
|
fPriorEnum = nullptr;
|
|
|
|
fPriorObject = nullptr;
|
2018-03-19 13:04:10 +00:00
|
|
|
fAttrDeprecated = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
fPrev = '\0';
|
|
|
|
fInChar = false;
|
|
|
|
fInCharCommentString = false;
|
|
|
|
fInComment = false;
|
2018-04-16 12:37:38 +00:00
|
|
|
fInDefine = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
fInEnum = false;
|
|
|
|
fInFunction = false;
|
|
|
|
fInString = false;
|
2017-12-20 19:53:21 +00:00
|
|
|
fFailed = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setBracketShortCuts(Bracket bracket) {
|
|
|
|
fInComment = Bracket::kSlashSlash == bracket || Bracket::kSlashStar == bracket;
|
|
|
|
fInString = Bracket::kString == bracket;
|
|
|
|
fInChar = Bracket::kChar == bracket;
|
|
|
|
fInCharCommentString = fInChar || fInComment || fInString;
|
|
|
|
}
|
|
|
|
|
2018-06-27 15:00:21 +00:00
|
|
|
Bracket topBracket() const;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
template <typename T>
|
2018-04-16 12:37:38 +00:00
|
|
|
string uniqueName(const unordered_map<string, T>& m, string typeName) {
|
2017-07-28 15:04:54 +00:00
|
|
|
string base(typeName.size() > 0 ? typeName : "_anonymous");
|
|
|
|
string name(base);
|
|
|
|
int anonCount = 1;
|
|
|
|
do {
|
|
|
|
auto iter = m.find(name);
|
|
|
|
if (iter == m.end()) {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
name = base + '_';
|
|
|
|
name += to_string(++anonCount);
|
|
|
|
} while (true);
|
|
|
|
// should never get here
|
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
void validate() const;
|
|
|
|
|
2017-09-19 21:39:32 +00:00
|
|
|
void writeDefinition(const Definition& def) {
|
|
|
|
if (def.length() > 1) {
|
|
|
|
this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeDefinition(const Definition& def, string name, int spaces) {
|
2017-09-19 21:39:32 +00:00
|
|
|
this->writeBlock((int) (def.fContentEnd - def.fContentStart), def.fContentStart);
|
|
|
|
this->writeSpace(spaces);
|
|
|
|
this->writeString(name);
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeEndTag() {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString("##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeEndTag(const char* tagType) {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString(string("#") + tagType + " ##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeEndTag(const char* tagType, const char* tagID, int spaces = 1) {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString(string("#") + tagType + " " + tagID);
|
|
|
|
this->writeSpace(spaces);
|
|
|
|
this->writeString("##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeEndTag(const char* tagType, string tagID, int spaces = 1) {
|
2017-09-19 21:39:32 +00:00
|
|
|
this->writeEndTag(tagType, tagID.c_str(), spaces);
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeIncompleteTag(const char* tagType, string tagID, int spaces = 1) {
|
2017-10-26 11:58:48 +00:00
|
|
|
this->writeString(string("#") + tagType + " " + tagID);
|
|
|
|
this->writeSpace(spaces);
|
|
|
|
this->writeString("incomplete");
|
|
|
|
this->writeSpace();
|
|
|
|
this->writeString("##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeIncompleteTag(const char* tagType) {
|
|
|
|
this->writeString(string("#") + tagType + " incomplete ##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
2017-09-19 21:39:32 +00:00
|
|
|
void writeTableHeader(const char* col1, size_t pad, const char* col2) {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString("#Table");
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString("#Legend");
|
|
|
|
this->lf(1);
|
|
|
|
string legend = "# ";
|
|
|
|
legend += col1;
|
|
|
|
if (pad > strlen(col1)) {
|
|
|
|
legend += string(pad - strlen(col1), ' ');
|
|
|
|
}
|
|
|
|
legend += " # ";
|
|
|
|
legend += col2;
|
|
|
|
legend += " ##";
|
|
|
|
this->writeString(legend);
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString("#Legend ##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeTableRow(size_t pad, string col1) {
|
2017-09-19 21:39:32 +00:00
|
|
|
this->lf(1);
|
|
|
|
string row = "# " + col1 + string(pad - col1.length(), ' ') + " # ##";
|
|
|
|
this->writeString(row);
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeTableRow(size_t pad1, string col1, size_t pad2, string col2) {
|
2018-01-26 17:56:22 +00:00
|
|
|
this->lf(1);
|
|
|
|
string row = "# " + col1 + string(pad1 - col1.length(), ' ') + " # " +
|
|
|
|
col2 + string(pad2 - col2.length(), ' ') + " ##";
|
|
|
|
this->writeString(row);
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
2017-09-19 21:39:32 +00:00
|
|
|
void writeTableTrailer() {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString("#Table ##");
|
|
|
|
this->lf(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTag(const char* tagType) {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeString("#");
|
|
|
|
this->writeString(tagType);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTagNoLF(const char* tagType, const char* tagID) {
|
|
|
|
this->writeString("#");
|
|
|
|
this->writeString(tagType);
|
|
|
|
this->writeSpace();
|
|
|
|
this->writeString(tagID);
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeTagNoLF(const char* tagType, string tagID) {
|
2017-09-19 21:39:32 +00:00
|
|
|
this->writeTagNoLF(tagType, tagID.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTag(const char* tagType, const char* tagID) {
|
|
|
|
this->lf(1);
|
|
|
|
this->writeTagNoLF(tagType, tagID);
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
void writeTag(const char* tagType, string tagID) {
|
2017-09-19 21:39:32 +00:00
|
|
|
this->writeTag(tagType, tagID.c_str());
|
|
|
|
}
|
|
|
|
|
2018-06-27 15:00:21 +00:00
|
|
|
void writeTagTable(string tagType, string body) {
|
|
|
|
this->writeTag(tagType.c_str());
|
|
|
|
this->writeSpace(1);
|
|
|
|
this->writeString("#");
|
|
|
|
this->writeSpace(1);
|
|
|
|
this->writeString(body);
|
|
|
|
this->writeSpace(1);
|
|
|
|
this->writeString("##");
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
protected:
|
|
|
|
static void ValidateKeyWords();
|
|
|
|
|
|
|
|
struct DefinitionMap {
|
2018-04-16 12:37:38 +00:00
|
|
|
unordered_map<string, Definition*>* fInclude;
|
2017-07-28 15:04:54 +00:00
|
|
|
MarkType fMarkType;
|
|
|
|
};
|
2017-10-09 19:45:33 +00:00
|
|
|
|
2018-03-19 13:04:10 +00:00
|
|
|
static const char gAttrDeprecated[];
|
|
|
|
static const size_t kAttrDeprecatedLen;
|
|
|
|
|
2018-06-07 13:59:07 +00:00
|
|
|
vector<DefinitionMap> fMaps;
|
2017-07-28 15:04:54 +00:00
|
|
|
unordered_map<string, Definition> fIncludeMap;
|
2018-04-16 12:37:38 +00:00
|
|
|
list<Definition> fGlobals;
|
2017-07-28 15:04:54 +00:00
|
|
|
unordered_map<string, IClassDefinition> fIClassMap;
|
2018-04-26 12:32:37 +00:00
|
|
|
unordered_map<string, Definition*> fIConstMap;
|
2018-04-16 12:37:38 +00:00
|
|
|
unordered_map<string, Definition*> fIDefineMap;
|
|
|
|
unordered_map<string, Definition*> fIEnumMap;
|
|
|
|
unordered_map<string, Definition*> fIFunctionMap;
|
|
|
|
unordered_map<string, Definition*> fIStructMap;
|
|
|
|
unordered_map<string, Definition*> fITemplateMap;
|
|
|
|
unordered_map<string, Definition*> fITypedefMap;
|
|
|
|
unordered_map<string, Definition*> fIUnionMap;
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition* fRootTopic;
|
2018-06-07 13:59:07 +00:00
|
|
|
Definition* fConstExpr;
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition* fInBrace;
|
2017-08-29 21:36:51 +00:00
|
|
|
Definition* fLastObject;
|
2018-01-04 21:11:51 +00:00
|
|
|
Definition* fPriorEnum;
|
2018-06-07 13:59:07 +00:00
|
|
|
Definition* fPriorObject;
|
2018-03-19 13:04:10 +00:00
|
|
|
const Definition* fAttrDeprecated;
|
2018-01-04 21:11:51 +00:00
|
|
|
int fPriorIndex;
|
2017-07-28 15:04:54 +00:00
|
|
|
const char* fIncludeWord;
|
|
|
|
char fPrev;
|
|
|
|
bool fInChar;
|
|
|
|
bool fInCharCommentString;
|
|
|
|
bool fInComment;
|
2018-04-16 12:37:38 +00:00
|
|
|
bool fInDefine;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool fInEnum;
|
|
|
|
bool fInFunction;
|
|
|
|
bool fInString;
|
2017-12-20 19:53:21 +00:00
|
|
|
bool fFailed;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
typedef ParserCommon INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IncludeWriter : public IncludeParser {
|
|
|
|
public:
|
|
|
|
enum class Word {
|
|
|
|
kStart,
|
|
|
|
kCap,
|
|
|
|
kFirst,
|
|
|
|
kUnderline,
|
|
|
|
kMixed,
|
|
|
|
};
|
|
|
|
|
2017-09-14 15:25:39 +00:00
|
|
|
enum class Phrase {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
enum class PunctuationState {
|
|
|
|
kStart,
|
|
|
|
kDelimiter,
|
2018-02-20 15:35:29 +00:00
|
|
|
kParen, // treated as a delimiter unless following a space, and followed by word
|
2017-07-28 15:04:54 +00:00
|
|
|
kPeriod,
|
2017-07-31 11:52:43 +00:00
|
|
|
kSpace,
|
2017-07-28 15:04:54 +00:00
|
|
|
};
|
|
|
|
|
2017-09-01 19:51:02 +00:00
|
|
|
enum class RefType {
|
|
|
|
kUndefined,
|
|
|
|
kNormal,
|
|
|
|
kExternal,
|
|
|
|
};
|
|
|
|
|
2018-02-08 19:45:18 +00:00
|
|
|
enum class SkipFirstLine {
|
|
|
|
kNo,
|
|
|
|
kYes,
|
|
|
|
};
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
enum class Wrote {
|
|
|
|
kNone,
|
|
|
|
kLF,
|
|
|
|
kChars,
|
|
|
|
};
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
enum class MemberPass {
|
|
|
|
kCount,
|
|
|
|
kOut,
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
enum class ItemState {
|
|
|
|
kNone,
|
|
|
|
kName,
|
|
|
|
kValue,
|
|
|
|
kComment,
|
|
|
|
};
|
|
|
|
|
2017-08-03 21:14:08 +00:00
|
|
|
struct IterState {
|
2017-10-09 19:45:33 +00:00
|
|
|
IterState (list<Definition>::iterator tIter, list<Definition>::iterator tIterEnd)
|
2017-08-03 21:14:08 +00:00
|
|
|
: fDefIter(tIter)
|
|
|
|
, fDefEnd(tIterEnd) {
|
|
|
|
}
|
|
|
|
list<Definition>::iterator fDefIter;
|
|
|
|
list<Definition>::iterator fDefEnd;
|
|
|
|
};
|
|
|
|
|
2017-08-29 21:36:51 +00:00
|
|
|
struct ParentPair {
|
|
|
|
const Definition* fParent;
|
|
|
|
const ParentPair* fPrev;
|
|
|
|
};
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
struct Preprocessor {
|
2018-04-03 19:31:59 +00:00
|
|
|
Preprocessor() {
|
|
|
|
reset();
|
2018-04-03 12:43:27 +00:00
|
|
|
}
|
2018-04-03 19:31:59 +00:00
|
|
|
|
|
|
|
void reset() {
|
|
|
|
fDefinition = nullptr;
|
|
|
|
fStart = nullptr;
|
|
|
|
fEnd = nullptr;
|
|
|
|
fWord = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Definition* fDefinition;
|
2018-04-03 12:43:27 +00:00
|
|
|
const char* fStart;
|
|
|
|
const char* fEnd;
|
|
|
|
bool fWord;
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
struct Item {
|
2018-05-30 13:21:49 +00:00
|
|
|
void reset() {
|
|
|
|
fName = "";
|
|
|
|
fValue = "";
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
string fName;
|
|
|
|
string fValue;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct LastItem {
|
|
|
|
const char* fStart;
|
|
|
|
const char* fEnd;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ItemLength {
|
|
|
|
int fCurName;
|
|
|
|
int fCurValue;
|
|
|
|
int fLongestName;
|
|
|
|
int fLongestValue;
|
|
|
|
};
|
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
IncludeWriter() : IncludeParser() {
|
|
|
|
this->reset();
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
~IncludeWriter() override {}
|
|
|
|
|
|
|
|
bool contentFree(int size, const char* data) const {
|
|
|
|
while (size > 0 && data[0] <= ' ') {
|
|
|
|
--size;
|
|
|
|
++data;
|
|
|
|
}
|
|
|
|
while (size > 0 && data[size - 1] <= ' ') {
|
|
|
|
--size;
|
|
|
|
}
|
|
|
|
return 0 == size;
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
bool checkChildCommentLength(const Definition* parent, MarkType childType) const;
|
|
|
|
void checkEnumLengths(const Definition& child, string enumName, ItemLength* length) const;
|
2018-05-30 13:21:49 +00:00
|
|
|
void constOut(const Definition* memberStart, const Definition* bmhConst);
|
|
|
|
void constSizeMembers(const RootDefinition* root);
|
2018-06-08 15:54:32 +00:00
|
|
|
bool defineOut(const Definition& );
|
2018-05-30 13:21:49 +00:00
|
|
|
bool descriptionOut(const Definition* def, SkipFirstLine , Phrase );
|
2018-05-16 11:07:07 +00:00
|
|
|
void enumHeaderOut(RootDefinition* root, const Definition& child);
|
|
|
|
string enumMemberComment(const Definition* currentEnumItem, const Definition& child) const;
|
|
|
|
const Definition* enumMemberForComment(const Definition* currentEnumItem) const;
|
|
|
|
ItemState enumMemberName(const Definition& child,
|
|
|
|
const Definition* token, Item* , LastItem* , const Definition** enumItem);
|
|
|
|
void enumMemberOut(const Definition* currentEnumItem, const Definition& child,
|
|
|
|
const Item& , Preprocessor& );
|
|
|
|
void enumMembersOut(Definition& child);
|
2018-04-03 12:43:27 +00:00
|
|
|
bool enumPreprocessor(Definition* token, MemberPass pass,
|
|
|
|
vector<IterState>& iterStack, IterState** iterState, Preprocessor* );
|
2017-07-28 15:04:54 +00:00
|
|
|
void enumSizeItems(const Definition& child);
|
2018-04-03 12:43:27 +00:00
|
|
|
bool findEnumSubtopic(string undername, const Definition** ) const;
|
2018-06-07 13:59:07 +00:00
|
|
|
void firstBlock(int size, const char* data);
|
|
|
|
bool firstBlockTrim(int size, const char* data);
|
2018-04-16 12:37:38 +00:00
|
|
|
Definition* findMemberCommentBlock(const vector<Definition*>& bmhChildren, string name) const;
|
2018-06-07 13:59:07 +00:00
|
|
|
Definition* findMethod(string name, RootDefinition* ) const;
|
|
|
|
|
|
|
|
void indentDeferred(IndentKind kind) {
|
|
|
|
if (fIndentNext) {
|
|
|
|
this->indentIn(kind);
|
|
|
|
fIndentNext = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
int lookupMethod(const PunctuationState punctuation, const Word word,
|
2017-10-09 19:45:33 +00:00
|
|
|
const int start, const int run, int lastWrite,
|
2017-09-21 16:31:06 +00:00
|
|
|
const char* data, bool hasIndirection);
|
2017-07-28 15:04:54 +00:00
|
|
|
int lookupReference(const PunctuationState punctuation, const Word word,
|
2017-10-09 19:45:33 +00:00
|
|
|
const int start, const int run, int lastWrite, const char last,
|
2017-07-28 15:04:54 +00:00
|
|
|
const char* data);
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* matchMemberName(string matchName, const Definition& child) const;
|
|
|
|
void methodOut(Definition* method, const Definition& child);
|
2017-08-29 21:36:51 +00:00
|
|
|
bool populate(Definition* def, ParentPair* parentPair, RootDefinition* root);
|
2017-07-28 15:04:54 +00:00
|
|
|
bool populate(BmhParser& bmhParser);
|
|
|
|
|
|
|
|
void reset() override {
|
|
|
|
INHERITED::resetCommon();
|
|
|
|
fBmhParser = nullptr;
|
2018-06-07 13:59:07 +00:00
|
|
|
fDeferComment = nullptr;
|
|
|
|
fBmhMethod = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
fEnumDef = nullptr;
|
2017-07-31 15:48:27 +00:00
|
|
|
fMethodDef = nullptr;
|
2018-05-30 13:21:49 +00:00
|
|
|
fBmhConst = nullptr;
|
|
|
|
fConstDef = nullptr;
|
2018-06-07 13:59:07 +00:00
|
|
|
fLastDescription = nullptr;
|
|
|
|
fStartSetter = nullptr;
|
2017-10-26 11:58:48 +00:00
|
|
|
fBmhStructDef = nullptr;
|
2018-06-07 13:59:07 +00:00
|
|
|
fContinuation = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
fInStruct = false;
|
2017-09-14 15:25:39 +00:00
|
|
|
fWroteMethod = false;
|
2017-10-26 11:58:48 +00:00
|
|
|
fIndentNext = false;
|
|
|
|
fPendingMethod = false;
|
2018-06-07 13:59:07 +00:00
|
|
|
fFirstWrite = false;
|
|
|
|
fStructEnded = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2018-05-30 13:21:49 +00:00
|
|
|
string resolveAlias(const Definition* );
|
2017-07-28 15:04:54 +00:00
|
|
|
string resolveMethod(const char* start, const char* end, bool first);
|
2017-09-01 19:51:02 +00:00
|
|
|
string resolveRef(const char* start, const char* end, bool first, RefType* refType);
|
2017-09-14 15:25:39 +00:00
|
|
|
Wrote rewriteBlock(int size, const char* data, Phrase phrase);
|
2018-06-07 13:59:07 +00:00
|
|
|
void setStart(const char* start, const Definition * );
|
|
|
|
void setStartBack(const char* start, const Definition * );
|
2017-08-03 21:14:08 +00:00
|
|
|
Definition* structMemberOut(const Definition* memberStart, const Definition& child);
|
2017-07-28 15:04:54 +00:00
|
|
|
void structOut(const Definition* root, const Definition& child,
|
|
|
|
const char* commentStart, const char* commentEnd);
|
2017-10-11 14:37:52 +00:00
|
|
|
void structSizeMembers(const Definition& child);
|
2018-06-08 15:54:32 +00:00
|
|
|
bool writeHeader(std::pair<const string, Definition>& );
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
2018-06-07 13:59:07 +00:00
|
|
|
vector<const Definition* > fICSStack;
|
2017-07-28 15:04:54 +00:00
|
|
|
BmhParser* fBmhParser;
|
|
|
|
Definition* fDeferComment;
|
2017-07-31 15:48:27 +00:00
|
|
|
const Definition* fBmhMethod;
|
2017-07-28 15:04:54 +00:00
|
|
|
const Definition* fEnumDef;
|
2017-07-31 15:48:27 +00:00
|
|
|
const Definition* fMethodDef;
|
2018-05-30 13:21:49 +00:00
|
|
|
const Definition* fBmhConst;
|
|
|
|
const Definition* fConstDef;
|
|
|
|
const Definition* fLastDescription;
|
2018-06-07 13:59:07 +00:00
|
|
|
const Definition* fStartSetter;
|
2018-05-16 11:07:07 +00:00
|
|
|
Definition* fBmhStructDef;
|
2017-07-28 15:04:54 +00:00
|
|
|
const char* fContinuation; // used to construct paren-qualified method name
|
|
|
|
int fAnonymousEnumCount;
|
|
|
|
int fEnumItemValueTab;
|
|
|
|
int fEnumItemCommentTab;
|
|
|
|
int fStructMemberTab;
|
2017-08-03 21:14:08 +00:00
|
|
|
int fStructValueTab;
|
2017-07-28 15:04:54 +00:00
|
|
|
int fStructCommentTab;
|
2018-05-30 13:21:49 +00:00
|
|
|
int fStructMemberLength;
|
|
|
|
int fConstValueTab;
|
|
|
|
int fConstCommentTab;
|
|
|
|
int fConstLength;
|
2018-06-07 13:59:07 +00:00
|
|
|
bool fInStruct; // set if struct is inside class
|
2017-09-14 15:25:39 +00:00
|
|
|
bool fWroteMethod;
|
2017-10-26 11:58:48 +00:00
|
|
|
bool fIndentNext;
|
|
|
|
bool fPendingMethod;
|
2018-06-07 13:59:07 +00:00
|
|
|
bool fFirstWrite; // set to write file information just after includes
|
|
|
|
bool fStructEnded; // allow resetting indent after struct is complete
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
typedef IncludeParser INHERITED;
|
|
|
|
};
|
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
class FiddleBase : public ParserCommon {
|
|
|
|
protected:
|
|
|
|
FiddleBase(BmhParser* bmh) : ParserCommon()
|
|
|
|
, fBmhParser(bmh)
|
|
|
|
, fContinuation(false)
|
|
|
|
, fTextOut(false)
|
|
|
|
, fPngOut(false)
|
|
|
|
{
|
2017-07-28 15:04:54 +00:00
|
|
|
this->reset();
|
|
|
|
}
|
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
void reset() override {
|
|
|
|
INHERITED::resetCommon();
|
|
|
|
}
|
|
|
|
|
2018-02-27 14:54:21 +00:00
|
|
|
Definition* findExample(string name) const { return fBmhParser->findExample(name); }
|
2017-10-31 19:44:45 +00:00
|
|
|
bool parseFiddles();
|
|
|
|
virtual bool pngOut(Definition* example) = 0;
|
|
|
|
virtual bool textOut(Definition* example, const char* stdOutStart,
|
|
|
|
const char* stdOutEnd) = 0;
|
|
|
|
|
|
|
|
BmhParser* fBmhParser; // must be writable; writes example hash
|
|
|
|
string fFullName;
|
|
|
|
bool fContinuation;
|
|
|
|
bool fTextOut;
|
|
|
|
bool fPngOut;
|
|
|
|
private:
|
|
|
|
typedef ParserCommon INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FiddleParser : public FiddleBase {
|
|
|
|
public:
|
|
|
|
FiddleParser(BmhParser* bmh) : FiddleBase(bmh) {
|
|
|
|
fTextOut = true;
|
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
|
|
|
|
bool parseFromFile(const char* path) override {
|
|
|
|
if (!INHERITED::parseSetup(path)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return parseFiddles();
|
|
|
|
}
|
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
private:
|
|
|
|
bool pngOut(Definition* example) override {
|
|
|
|
return true;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
bool textOut(Definition* example, const char* stdOutStart,
|
|
|
|
const char* stdOutEnd) override;
|
|
|
|
|
|
|
|
typedef FiddleBase INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Catalog : public FiddleBase {
|
|
|
|
public:
|
|
|
|
Catalog(BmhParser* bmh) : FiddleBase(bmh) {}
|
|
|
|
|
2018-04-16 12:37:38 +00:00
|
|
|
bool appendFile(string path);
|
2017-10-31 19:44:45 +00:00
|
|
|
bool closeCatalog();
|
|
|
|
bool openCatalog(const char* inDir, const char* outDir);
|
2017-12-11 21:03:17 +00:00
|
|
|
bool openStatus(const char* inDir, const char* outDir);
|
2017-10-31 19:44:45 +00:00
|
|
|
|
|
|
|
bool parseFromFile(const char* path) override ;
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
2017-10-31 19:44:45 +00:00
|
|
|
bool pngOut(Definition* example) override;
|
|
|
|
bool textOut(Definition* example, const char* stdOutStart,
|
|
|
|
const char* stdOutEnd) override;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
string fDocsDir;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2017-10-31 19:44:45 +00:00
|
|
|
typedef FiddleBase INHERITED;
|
2017-07-28 15:04:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class HackParser : public ParserCommon {
|
|
|
|
public:
|
2018-01-30 15:08:57 +00:00
|
|
|
HackParser(const BmhParser& bmhParser)
|
|
|
|
: ParserCommon()
|
|
|
|
, fBmhParser(bmhParser) {
|
2017-07-28 15:04:54 +00:00
|
|
|
this->reset();
|
|
|
|
}
|
|
|
|
|
2018-02-01 14:37:32 +00:00
|
|
|
void addOneLiner(const Definition* defTable, const Definition* child, bool hasLine,
|
|
|
|
bool lfAfter);
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
bool parseFromFile(const char* path) override {
|
|
|
|
if (!INHERITED::parseSetup(path)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return hackFiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset() override {
|
|
|
|
INHERITED::resetCommon();
|
|
|
|
}
|
|
|
|
|
2018-01-30 15:08:57 +00:00
|
|
|
string searchTable(const Definition* tableHolder, const Definition* match);
|
|
|
|
|
|
|
|
void topicIter(const Definition* );
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
2018-01-30 15:08:57 +00:00
|
|
|
const BmhParser& fBmhParser;
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* fClasses;
|
2018-02-01 14:37:32 +00:00
|
|
|
const Definition* fConstants;
|
2018-01-30 15:08:57 +00:00
|
|
|
const Definition* fConstructors;
|
|
|
|
const Definition* fMemberFunctions;
|
2018-02-01 14:37:32 +00:00
|
|
|
const Definition* fMembers;
|
|
|
|
const Definition* fOperators;
|
|
|
|
const Definition* fRelatedFunctions;
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* fStructs;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool hackFiles();
|
|
|
|
|
|
|
|
typedef ParserCommon INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MdOut : public ParserCommon {
|
|
|
|
public:
|
2018-05-16 11:07:07 +00:00
|
|
|
struct SubtopicDescriptions {
|
|
|
|
string fName;
|
|
|
|
string fOneLiner;
|
|
|
|
string fDetails;
|
|
|
|
};
|
|
|
|
|
|
|
|
MdOut(BmhParser& bmh) : ParserCommon()
|
2017-07-28 15:04:54 +00:00
|
|
|
, fBmhParser(bmh) {
|
|
|
|
this->reset();
|
2018-05-16 11:07:07 +00:00
|
|
|
this->addPopulators();
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2018-04-03 12:43:27 +00:00
|
|
|
bool buildReferences(const IncludeParser& , const char* docDir, const char* mdOutDirOrFile);
|
2018-01-04 21:11:51 +00:00
|
|
|
bool buildStatus(const char* docDir, const char* mdOutDir);
|
2018-05-16 11:07:07 +00:00
|
|
|
void checkAnchors();
|
2018-02-01 14:37:32 +00:00
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
private:
|
|
|
|
enum class TableState {
|
|
|
|
kNone,
|
|
|
|
kRow,
|
|
|
|
kColumn,
|
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
struct AnchorDef {
|
|
|
|
string fDef;
|
|
|
|
MarkType fMarkType;
|
2018-02-06 14:41:53 +00:00
|
|
|
};
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
void addPopulators();
|
2017-07-28 15:04:54 +00:00
|
|
|
string addReferences(const char* start, const char* end, BmhParser::Resolvable );
|
2018-05-16 11:07:07 +00:00
|
|
|
string anchorDef(string def, string name);
|
|
|
|
string anchorLocalRef(string ref, string name);
|
|
|
|
string anchorRef(string def, string name);
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
bool buildRefFromFile(const char* fileName, const char* outDir);
|
2018-03-12 12:26:45 +00:00
|
|
|
bool checkParamReturnBody(const Definition* def);
|
2018-05-16 11:07:07 +00:00
|
|
|
Definition* checkParentsForMatch(Definition* test, string ref) const;
|
|
|
|
void childrenOut(Definition* def, const char* contentStart);
|
|
|
|
Definition* csParent();
|
2017-09-14 15:25:39 +00:00
|
|
|
const Definition* findParamType();
|
2018-05-16 11:07:07 +00:00
|
|
|
string getMemberTypeName(const Definition* def, string* memberType);
|
|
|
|
static bool HasDetails(const Definition* def);
|
|
|
|
void htmlOut(string );
|
2018-04-16 12:37:38 +00:00
|
|
|
const Definition* isDefined(const TextParser& , string ref, BmhParser::Resolvable );
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* isDefinedByParent(RootDefinition* root, string ref);
|
2017-07-28 15:04:54 +00:00
|
|
|
string linkName(const Definition* ) const;
|
2018-05-16 11:07:07 +00:00
|
|
|
string linkRef(string leadingSpaces, const Definition*, string ref, BmhParser::Resolvable );
|
|
|
|
void markTypeOut(Definition* , const Definition** prior);
|
2017-10-09 19:45:33 +00:00
|
|
|
void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); }
|
2017-07-28 15:04:54 +00:00
|
|
|
void mdHeaderOutLF(int depth, int lf);
|
2018-02-01 14:37:32 +00:00
|
|
|
bool parseFromFile(const char* path) override { return true; }
|
2018-05-16 11:07:07 +00:00
|
|
|
void populateOne(Definition* def,
|
|
|
|
unordered_map<string, RootDefinition::SubtopicContents>& populator);
|
|
|
|
void populateTables(const Definition* def, RootDefinition* );
|
2018-02-01 14:37:32 +00:00
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
SubtopicDescriptions& populator(string key) {
|
2018-02-06 14:41:53 +00:00
|
|
|
auto entry = fPopulators.find(key);
|
|
|
|
// FIXME: this should have been detected earlier
|
|
|
|
SkASSERT(fPopulators.end() != entry);
|
|
|
|
return entry->second;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reset() override {
|
|
|
|
INHERITED::resetCommon();
|
2017-08-03 21:14:08 +00:00
|
|
|
fEnumClass = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
fMethod = nullptr;
|
|
|
|
fRoot = nullptr;
|
2018-05-16 11:07:07 +00:00
|
|
|
fSubtopic = nullptr;
|
2017-09-14 15:25:39 +00:00
|
|
|
fLastParam = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
fTableState = TableState::kNone;
|
2018-03-12 12:26:45 +00:00
|
|
|
fAddRefFailed = false;
|
2017-07-28 15:04:54 +00:00
|
|
|
fHasFiddle = false;
|
|
|
|
fInDescription = false;
|
|
|
|
fInList = false;
|
2018-04-03 12:43:27 +00:00
|
|
|
fResolveAndIndent = false;
|
|
|
|
fLiteralAndIndent = false;
|
2018-05-16 11:07:07 +00:00
|
|
|
fLastDef = nullptr;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
2017-10-26 11:58:48 +00:00
|
|
|
BmhParser::Resolvable resolvable(const Definition* definition) const {
|
|
|
|
MarkType markType = definition->fMarkType;
|
|
|
|
if (MarkType::kCode == markType) {
|
|
|
|
for (auto child : definition->fChildren) {
|
|
|
|
if (MarkType::kLiteral == child->fMarkType) {
|
|
|
|
return BmhParser::Resolvable::kLiteral;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-09 19:45:33 +00:00
|
|
|
if ((MarkType::kExample == markType
|
2017-07-28 15:04:54 +00:00
|
|
|
|| MarkType::kFunction == markType) && fHasFiddle) {
|
|
|
|
return BmhParser::Resolvable::kNo;
|
|
|
|
}
|
2018-04-16 12:37:38 +00:00
|
|
|
return BmhParser::kMarkProps[(int) markType].fResolve;
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void resolveOut(const char* start, const char* end, BmhParser::Resolvable );
|
2018-05-16 11:07:07 +00:00
|
|
|
void rowOut(const char * name, string description, bool literalName);
|
|
|
|
|
|
|
|
void subtopicOut(string name);
|
|
|
|
void subtopicsOut(Definition* def);
|
|
|
|
void summaryOut(const Definition* def, MarkType , string name);
|
|
|
|
string tableDataCodeDef(const Definition* def);
|
|
|
|
string tableDataCodeDef(string def, string name);
|
|
|
|
string tableDataCodeLocalRef(string name);
|
|
|
|
string tableDataCodeLocalRef(string ref, string name);
|
|
|
|
string tableDataCodeRef(const Definition* ref);
|
|
|
|
string tableDataCodeRef(string ref, string name);
|
2018-02-01 14:37:32 +00:00
|
|
|
|
|
|
|
vector<const Definition*> fClassStack;
|
2018-05-16 11:07:07 +00:00
|
|
|
unordered_map<string, vector<AnchorDef> > fAllAnchorDefs;
|
|
|
|
unordered_map<string, vector<string> > fAllAnchorRefs;
|
2017-07-28 15:04:54 +00:00
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
BmhParser& fBmhParser;
|
2017-08-03 21:14:08 +00:00
|
|
|
const Definition* fEnumClass;
|
2018-05-16 11:07:07 +00:00
|
|
|
const Definition* fLastDef;
|
2017-07-28 15:04:54 +00:00
|
|
|
Definition* fMethod;
|
2018-05-16 11:07:07 +00:00
|
|
|
RootDefinition* fRoot; // used in generating populated tables; always struct or class
|
|
|
|
RootDefinition* fSubtopic; // used in resolving symbols
|
2017-09-14 15:25:39 +00:00
|
|
|
const Definition* fLastParam;
|
2017-07-28 15:04:54 +00:00
|
|
|
TableState fTableState;
|
2018-05-16 11:07:07 +00:00
|
|
|
unordered_map<string, SubtopicDescriptions> fPopulators;
|
|
|
|
unordered_map<string, string> fPhraseParams;
|
2018-03-12 12:26:45 +00:00
|
|
|
bool fAddRefFailed;
|
2017-07-28 15:04:54 +00:00
|
|
|
bool fHasFiddle;
|
|
|
|
bool fInDescription; // FIXME: for now, ignore unfound camelCase in description since it may
|
|
|
|
// be defined in example which at present cannot be linked to
|
|
|
|
bool fInList;
|
2018-04-03 12:43:27 +00:00
|
|
|
bool fLiteralAndIndent;
|
|
|
|
bool fResolveAndIndent;
|
2018-05-16 11:07:07 +00:00
|
|
|
bool fOddRow;
|
|
|
|
bool fHasDetails;
|
2017-07-28 15:04:54 +00:00
|
|
|
typedef ParserCommon INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// some methods cannot be trivially parsed; look for class-name / ~ / operator
|
|
|
|
class MethodParser : public TextParser {
|
|
|
|
public:
|
2018-04-16 12:37:38 +00:00
|
|
|
MethodParser(string className, string fileName,
|
2017-07-28 15:04:54 +00:00
|
|
|
const char* start, const char* end, int lineCount)
|
|
|
|
: TextParser(fileName, start, end, lineCount)
|
|
|
|
, fClassName(className) {
|
|
|
|
}
|
|
|
|
|
2017-12-11 21:03:17 +00:00
|
|
|
~MethodParser() override {}
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
void skipToMethodStart() {
|
|
|
|
if (!fClassName.length()) {
|
|
|
|
this->skipToAlphaNum();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
|
|
|
|
this->next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:07:07 +00:00
|
|
|
void skipToMethodEnd(BmhParser::Resolvable resolvable) {
|
2017-07-28 15:04:54 +00:00
|
|
|
if (this->eof()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (fClassName.length()) {
|
|
|
|
if ('~' == this->peek()) {
|
|
|
|
this->next();
|
|
|
|
if (!this->startsWith(fClassName.c_str())) {
|
|
|
|
--fChar;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-05-16 11:07:07 +00:00
|
|
|
if (BmhParser::Resolvable::kSimple != resolvable
|
|
|
|
&& (this->startsWith(fClassName.c_str()) || this->startsWith("operator"))) {
|
2017-11-27 15:44:06 +00:00
|
|
|
const char* ptr = this->anyOf("\n (");
|
2017-07-28 15:04:54 +00:00
|
|
|
if (ptr && '(' == *ptr) {
|
|
|
|
this->skipToEndBracket(')');
|
|
|
|
SkAssertResult(')' == this->next());
|
2017-11-27 15:44:06 +00:00
|
|
|
this->skipExact("_const");
|
2017-07-28 15:04:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this->startsWith("Sk") && this->wordEndsWith(".h")) { // allow include refs
|
2018-04-16 12:37:38 +00:00
|
|
|
this->skipToNonName();
|
2017-07-28 15:04:54 +00:00
|
|
|
} else {
|
|
|
|
this->skipFullName();
|
2017-11-27 15:44:06 +00:00
|
|
|
if (this->endsWith("operator")) {
|
|
|
|
const char* ptr = this->anyOf("\n (");
|
|
|
|
if (ptr && '(' == *ptr) {
|
|
|
|
this->skipToEndBracket(')');
|
|
|
|
SkAssertResult(')' == this->next());
|
|
|
|
this->skipExact("_const");
|
|
|
|
}
|
|
|
|
}
|
2017-07-28 15:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
typedef TextParser INHERITED;
|
|
|
|
};
|
|
|
|
|
2018-01-11 15:35:44 +00:00
|
|
|
bool SelfCheck(const BmhParser& );
|
|
|
|
|
2017-07-28 15:04:54 +00:00
|
|
|
#endif
|
2018-04-26 12:32:37 +00:00
|
|
|
|