5c11d5c084
Verified that running bookmaker produces an identical fiddle.json before and after this change. Bug: skia: Change-Id: I1aa7477348a5f8c362201199b130508c2818116f Reviewed-on: https://skia-review.googlesource.com/c/188303 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
362 lines
9.0 KiB
C++
362 lines
9.0 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 parserCommon_DEFINED
|
|
#define parserCommon_DEFINED
|
|
|
|
#include "SkData.h"
|
|
#include "SkJSON.h"
|
|
|
|
#include "definition.h"
|
|
#include "textParser.h"
|
|
|
|
#include <memory>
|
|
|
|
enum class StatusFilter {
|
|
kCompleted,
|
|
kInProgress,
|
|
kUnknown,
|
|
};
|
|
|
|
class ParserCommon : public TextParser {
|
|
public:
|
|
enum class OneFile {
|
|
kNo,
|
|
kYes,
|
|
};
|
|
|
|
enum class OneLine {
|
|
kNo,
|
|
kYes,
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
ParserCommon() : TextParser()
|
|
, fParent(nullptr)
|
|
, fDebugOut(false)
|
|
, fValidate(false)
|
|
, fReturnOnWrite(false)
|
|
{
|
|
}
|
|
|
|
~ParserCommon() override {
|
|
}
|
|
|
|
void addDefinition(Definition* def) {
|
|
fParent->fChildren.push_back(def);
|
|
fParent = def;
|
|
}
|
|
|
|
void checkLineLength(size_t len, const char* str);
|
|
static string ConvertRef(const string str, bool first);
|
|
static void CopyToFile(string oldFile, string newFile);
|
|
static char* FindDateTime(char* buffer, int size);
|
|
static string HtmlFileName(string bmhFileName);
|
|
|
|
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();
|
|
}
|
|
|
|
void indentToColumn(int column) {
|
|
SkASSERT(column >= fColumn);
|
|
SkASSERT(!fReturnOnWrite);
|
|
SkASSERT(column < 80);
|
|
FPRINTF("%*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() {
|
|
SkASSERT(!fReturnOnWrite);
|
|
fLinefeeds = 0;
|
|
fSpaces = 0;
|
|
fColumn = 0;
|
|
fPendingSpace = 0;
|
|
}
|
|
|
|
bool parseFile(const char* file, const char* suffix, OneFile );
|
|
bool parseStatus(const char* file, const char* suffix, StatusFilter filter);
|
|
virtual bool parseFromFile(const char* path) = 0;
|
|
bool parseSetup(const char* path);
|
|
|
|
void popObject() {
|
|
fParent->fContentEnd = fParent->fTerminator = fChar;
|
|
fParent = fParent->fParent;
|
|
}
|
|
|
|
static char* ReadToBuffer(string filename, int* size);
|
|
|
|
virtual void reset() = 0;
|
|
|
|
void resetCommon() {
|
|
fLine = fChar = fStart;
|
|
fLineCount = 0;
|
|
fLinesWritten = 1;
|
|
fParent = nullptr;
|
|
fIndent = 0;
|
|
fOut = nullptr;
|
|
fMaxLF = 2;
|
|
fPendingLF = 0;
|
|
fPendingSpace = 0;
|
|
fOutdentNext = false;
|
|
fWritingIncludes = false;
|
|
fDebugWriteCodeBlock = false;
|
|
nl();
|
|
}
|
|
|
|
void setAsParent(Definition* definition) {
|
|
if (fParent) {
|
|
fParent->fChildren.push_back(definition);
|
|
definition->fParent = fParent;
|
|
}
|
|
fParent = definition;
|
|
}
|
|
|
|
void singleLF() {
|
|
fMaxLF = 1;
|
|
}
|
|
|
|
void stringAppend(string& result, char ch) const;
|
|
void stringAppend(string& result, string str) const;
|
|
void stringAppend(string& result, const Definition* ) const;
|
|
|
|
void writeBlock(int size, const char* data) {
|
|
SkAssertResult(writeBlockTrim(size, data));
|
|
}
|
|
|
|
bool writeBlockIndent(int size, const char* data, bool ignoreIndent);
|
|
|
|
void writeBlockSeparator() {
|
|
this->writeString(
|
|
"# ------------------------------------------------------------------------------");
|
|
this->lf(2);
|
|
}
|
|
|
|
bool writeBlockTrim(int size, const char* data);
|
|
|
|
void writeCommentHeader() {
|
|
this->lf(2);
|
|
this->writeString("/**");
|
|
this->writeSpace();
|
|
}
|
|
|
|
void writeCommentTrailer(OneLine oneLine) {
|
|
if (OneLine::kNo == oneLine) {
|
|
this->lf(1);
|
|
} else {
|
|
this->writeSpace();
|
|
}
|
|
this->writeString("*/");
|
|
this->lfcr();
|
|
}
|
|
|
|
void writePending();
|
|
|
|
// write a pending space, so that two consecutive calls
|
|
// don't double write, and trailing spaces on lines aren't written
|
|
void writeSpace(int count = 1) {
|
|
SkASSERT(!fReturnOnWrite);
|
|
SkASSERT(!fPendingLF);
|
|
SkASSERT(!fLinefeeds);
|
|
SkASSERT(fColumn > 0);
|
|
SkASSERT(!fSpaces);
|
|
fPendingSpace = count;
|
|
}
|
|
|
|
void writeString(const char* str);
|
|
|
|
void writeString(string str) {
|
|
this->writeString(str.c_str());
|
|
}
|
|
|
|
static bool WrittenFileDiffers(string filename, string readname);
|
|
|
|
unordered_map<string, sk_sp<SkData>> fRawData;
|
|
unordered_map<string, vector<char>> fLFOnly;
|
|
vector<IndentState> fIndentStack;
|
|
Definition* fParent;
|
|
FILE* fOut;
|
|
string fRawFilePathDir;
|
|
int fLinefeeds; // number of linefeeds last written, zeroed on non-space
|
|
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
|
|
size_t fLinesWritten; // as opposed to fLineCount, number of lines read
|
|
char fLastChar; // last written
|
|
bool fDebugOut; // set true to write to std out
|
|
bool fValidate; // set true to check anchor defs and refs
|
|
bool fOutdentNext; // set at end of embedded struct to prevent premature outdent
|
|
bool fWroteSomething; // used to detect empty content; an alternative source is preferable
|
|
bool fReturnOnWrite; // used to detect non-empty content; allowing early return
|
|
bool fWritingIncludes; // set true when writing includes to check >100 columns
|
|
mutable bool fDebugWriteCodeBlock;
|
|
|
|
private:
|
|
typedef TextParser INHERITED;
|
|
};
|
|
|
|
struct JsonStatus {
|
|
const skjson::ArrayValue* fArray;
|
|
const skjson::Value* fArrayIter;
|
|
const skjson::ObjectValue* fObject;
|
|
const skjson::Member* fObjectIter;
|
|
string fName;
|
|
StatusFilter fStatusFilter;
|
|
|
|
static JsonStatus Make(const skjson::Value& value, string name, StatusFilter filter) {
|
|
JsonStatus status = { value, nullptr, value, nullptr, name, filter };
|
|
status.reset();
|
|
return status;
|
|
}
|
|
|
|
void reset() {
|
|
fArrayIter = fArray ? fArray->begin() : nullptr;
|
|
fObjectIter = fObject ? fObject->begin() : nullptr;
|
|
}
|
|
|
|
bool atEnd() const {
|
|
if (fArray) {
|
|
return fArrayIter == fArray->end();
|
|
} else if (fObject) {
|
|
return fObjectIter == fObject->end();
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void advance() {
|
|
if (fArrayIter) {
|
|
fArrayIter++;
|
|
} else if (fObjectIter) {
|
|
fObjectIter++;
|
|
}
|
|
}
|
|
|
|
const skjson::Value& current() const {
|
|
if (fArrayIter) {
|
|
return *fArrayIter;
|
|
} else {
|
|
SkASSERT(fObjectIter);
|
|
return fObjectIter->fValue;
|
|
}
|
|
}
|
|
};
|
|
|
|
class JsonCommon : public ParserCommon {
|
|
public:
|
|
bool empty() { return fStack.empty(); }
|
|
bool parseFromFile(const char* path) override;
|
|
|
|
void reset() override {
|
|
fStack.clear();
|
|
INHERITED::resetCommon();
|
|
}
|
|
|
|
vector<JsonStatus> fStack;
|
|
std::unique_ptr<skjson::DOM> fDom;
|
|
private:
|
|
typedef ParserCommon INHERITED;
|
|
};
|
|
|
|
class StatusIter : public JsonCommon {
|
|
public:
|
|
StatusIter(const char* statusFile, const char* suffix, StatusFilter);
|
|
~StatusIter() override {}
|
|
string baseDir();
|
|
bool next(string* file, StatusFilter* filter);
|
|
private:
|
|
const char* fSuffix;
|
|
StatusFilter fFilter;
|
|
};
|
|
|
|
class HackParser : public ParserCommon {
|
|
public:
|
|
HackParser(const BmhParser& bmhParser)
|
|
: ParserCommon()
|
|
, fBmhParser(bmhParser) {
|
|
this->reset();
|
|
}
|
|
|
|
bool parseFromFile(const char* path) override {
|
|
if (!INHERITED::parseSetup(path)) {
|
|
return false;
|
|
}
|
|
return hackFiles();
|
|
}
|
|
|
|
void reset() override {
|
|
INHERITED::resetCommon();
|
|
}
|
|
|
|
void replaceWithPop(const Definition* );
|
|
|
|
private:
|
|
const BmhParser& fBmhParser;
|
|
bool hackFiles();
|
|
|
|
typedef ParserCommon INHERITED;
|
|
};
|
|
|
|
#endif
|