aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/bookmaker
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bookmaker')
-rw-r--r--tools/bookmaker/bookmaker.cpp391
-rw-r--r--tools/bookmaker/bookmaker.h95
-rw-r--r--tools/bookmaker/cataloger.cpp4
-rw-r--r--tools/bookmaker/definition.cpp254
-rw-r--r--tools/bookmaker/includeParser.cpp22
-rw-r--r--tools/bookmaker/includeWriter.cpp49
-rw-r--r--tools/bookmaker/mdOut.cpp26
7 files changed, 505 insertions, 336 deletions
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index 02dbbc1961..91e4cc2b23 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -6,6 +6,7 @@
*/
#include "bookmaker.h"
+#include "SkOSPath.h"
#ifdef SK_BUILD_FOR_WIN
#include <Windows.h>
@@ -189,7 +190,7 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
if (!typeNameBuilder.size()) {
return this->reportError<bool>("unnamed topic");
}
- fTopics.emplace_front(markType, defStart, fLineCount, fParent);
+ fTopics.emplace_front(markType, defStart, fLineCount, fParent, fMC);
RootDefinition* rootDefinition = &fTopics.front();
definition = rootDefinition;
definition->fFileName = fFileName;
@@ -277,6 +278,7 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
// may be one-liner
case MarkType::kNoExample:
case MarkType::kParam:
+ case MarkType::kPhraseDef:
case MarkType::kReturn:
case MarkType::kToDo:
if (hasEnd) {
@@ -289,22 +291,37 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
if (!this->popParentStack(fParent)) { // if not one liner, pop
return false;
}
- if (MarkType::kParam == markType || MarkType::kReturn == markType) {
+ if (MarkType::kParam == markType || MarkType::kReturn == markType
+ || MarkType::kPhraseDef == markType) {
if (!this->checkParamReturn(definition)) {
return false;
}
}
+ if (MarkType::kPhraseDef == markType) {
+ string key = definition->fName;
+ if (fPhraseMap.end() != fPhraseMap.find(key)) {
+ this->reportError<bool>("duplicate phrase key");
+ }
+ fPhraseMap[key] = definition;
+ }
} else {
- fMarkup.emplace_front(markType, defStart, fLineCount, fParent);
+ fMarkup.emplace_front(markType, defStart, fLineCount, fParent, fMC);
definition = &fMarkup.front();
definition->fName = typeNameBuilder[0];
definition->fFiddle = fParent->fFiddle;
definition->fContentStart = fChar;
- definition->fContentEnd = this->trimmedBracketEnd(fMC);
- this->skipToEndBracket(fMC);
+ string endBracket;
+ endBracket += fMC;
+ endBracket += fMC;
+ definition->fContentEnd = this->trimmedBracketEnd(endBracket);
+ this->skipToEndBracket(endBracket.c_str());
SkAssertResult(fMC == this->next());
SkAssertResult(fMC == this->next());
definition->fTerminator = fChar;
+ TextParser checkForChildren(definition);
+ if (checkForChildren.strnchr(fMC, definition->fContentEnd)) {
+ this->reportError<bool>("put ## on separate line");
+ }
fParent->fChildren.push_back(definition);
}
break;
@@ -334,10 +351,11 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
return this->reportError<bool>("missing example body");
}
}
- definition->setWrapper();
+// can't do this here; phrase refs may not have been defined yet
+// this->setWrapper(definition);
}
} else {
- fMarkup.emplace_front(markType, defStart, fLineCount, fParent);
+ fMarkup.emplace_front(markType, defStart, fLineCount, fParent, fMC);
definition = &fMarkup.front();
definition->fContentStart = fChar;
definition->fName = typeNameBuilder[0];
@@ -395,7 +413,7 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
} else if (!hasEnd && MarkType::kAnchor == markType) {
return this->reportError<bool>("anchor line must have end element last");
}
- fMarkup.emplace_front(markType, defStart, fLineCount, fParent);
+ fMarkup.emplace_front(markType, defStart, fLineCount, fParent, fMC);
definition = &fMarkup.front();
definition->fName = typeNameBuilder[0];
definition->fFiddle = Definition::NormalizedName(typeNameBuilder[0]);
@@ -405,7 +423,7 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
fParent->fChildren.push_back(definition);
if (MarkType::kAnchor == markType) {
this->skipToEndBracket(fMC);
- fMarkup.emplace_front(MarkType::kLink, fChar, fLineCount, definition);
+ fMarkup.emplace_front(MarkType::kLink, fChar, fLineCount, definition, fMC);
SkAssertResult(fMC == this->next());
this->skipWhiteSpace();
Definition* link = &fMarkup.front();
@@ -437,7 +455,7 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
if (fMC != this->next() || fMC != this->next()) {
return this->reportError<bool>("expected ## to delineate line");
}
- fMarkup.emplace_front(MarkType::kText, start, fLineCount, definition);
+ fMarkup.emplace_front(MarkType::kText, start, fLineCount, definition, fMC);
Definition* text = &fMarkup.front();
text->fContentStart = start;
text->fContentEnd = end;
@@ -690,7 +708,8 @@ bool BmhParser::collectExternals() {
const char* wordStart = fChar;
this->skipToNonAlphaNum();
if (fChar - wordStart > 0) {
- fExternals.emplace_front(MarkType::kExternal, wordStart, fChar, fLineCount, fParent);
+ fExternals.emplace_front(MarkType::kExternal, wordStart, fChar, fLineCount, fParent,
+ fMC);
RootDefinition* definition = &fExternals.front();
definition->fFileName = fFileName;
definition->fName = string(wordStart ,fChar - wordStart);
@@ -700,10 +719,10 @@ bool BmhParser::collectExternals() {
return true;
}
-static bool dump_examples(FILE* fiddleOut, const Definition& def, bool* continuation) {
+bool BmhParser::dumpExamples(FILE* fiddleOut, Definition& def, bool* continuation) const {
if (MarkType::kExample == def.fMarkType) {
string result;
- if (!def.exampleToScript(&result, Definition::ExampleOptions::kAll)) {
+ if (!this->exampleToScript(&def, BmhParser::ExampleOptions::kAll, &result)) {
return false;
}
if (result.length() > 0) {
@@ -719,7 +738,7 @@ static bool dump_examples(FILE* fiddleOut, const Definition& def, bool* continua
return true;
}
for (auto& child : def.fChildren ) {
- if (!dump_examples(fiddleOut, *child, continuation)) {
+ if (!this->dumpExamples(fiddleOut, *child, continuation)) {
return false;
}
}
@@ -738,7 +757,7 @@ bool BmhParser::dumpExamples(const char* fiddleJsonFileName) const {
if (topic.second->fParent) {
continue;
}
- dump_examples(fiddleOut, *topic.second, &continuation);
+ this->dumpExamples(fiddleOut, *topic.second, &continuation);
}
fprintf(fiddleOut, "\n}\n");
fclose(fiddleOut);
@@ -767,6 +786,262 @@ bool BmhParser::endTableColumn(const char* end, const char* terminator) {
return true;
}
+static size_t count_indent(const string& text, size_t test, size_t end) {
+ size_t result = test;
+ while (test < end) {
+ if (' ' != text[test]) {
+ break;
+ }
+ ++test;
+ }
+ return test - result;
+}
+
+static void add_code(const string& text, int pos, int end,
+ size_t outIndent, size_t textIndent, string& example) {
+ do {
+ // fix this to move whole paragraph in, out, but preserve doc indent
+ int nextIndent = count_indent(text, pos, end);
+ size_t len = text.find('\n', pos);
+ if (string::npos == len) {
+ len = end;
+ }
+ if ((size_t) (pos + nextIndent) < len) {
+ size_t indent = outIndent + nextIndent;
+ SkASSERT(indent >= textIndent);
+ indent -= textIndent;
+ for (size_t index = 0; index < indent; ++index) {
+ example += ' ';
+ }
+ pos += nextIndent;
+ while ((size_t) pos < len) {
+ example += '"' == text[pos] ? "\\\"" :
+ '\\' == text[pos] ? "\\\\" :
+ text.substr(pos, 1);
+ ++pos;
+ }
+ example += "\\n";
+ } else {
+ pos += nextIndent;
+ }
+ if ('\n' == text[pos]) {
+ ++pos;
+ }
+ } while (pos < end);
+}
+
+bool BmhParser::exampleToScript(Definition* def, ExampleOptions exampleOptions,
+ string* result) const {
+ bool hasFiddle = true;
+ const Definition* platform = def->hasChild(MarkType::kPlatform);
+ if (platform) {
+ TextParser platParse(platform);
+ hasFiddle = !platParse.strnstr("!fiddle", platParse.fEnd);
+ }
+ if (!hasFiddle) {
+ *result = "";
+ return true;
+ }
+ string text = this->extractText(def, TrimExtract::kNo);
+ bool textOut = string::npos != text.find("SkDebugf(")
+ || string::npos != text.find("dump(")
+ || string::npos != text.find("dumpHex(");
+ string heightStr = "256";
+ string widthStr = "256";
+ string normalizedName(def->fFiddle);
+ string code;
+ string imageStr = "0";
+ string srgbStr = "false";
+ string durationStr = "0";
+ for (auto iter : def->fChildren) {
+ switch (iter->fMarkType) {
+ case MarkType::kDuration:
+ durationStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
+ break;
+ case MarkType::kHeight:
+ heightStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
+ break;
+ case MarkType::kWidth:
+ widthStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
+ break;
+ case MarkType::kDescription:
+ // ignore for now
+ break;
+ case MarkType::kFunction: {
+ // emit this, but don't wrap this in draw()
+ string funcText = this->extractText(&*iter, TrimExtract::kNo);
+ size_t pos = 0;
+ while (pos < funcText.length() && ' ' > funcText[pos]) {
+ ++pos;
+ }
+ size_t indent = count_indent(funcText, pos, funcText.length());
+ add_code(funcText, pos, funcText.length(), 0, indent, code);
+ code += "\\n";
+ } break;
+ case MarkType::kComment:
+ break;
+ case MarkType::kImage:
+ imageStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
+ break;
+ case MarkType::kToDo:
+ break;
+ case MarkType::kBug:
+ case MarkType::kMarkChar:
+ case MarkType::kPlatform:
+ case MarkType::kPhraseRef:
+ // ignore for now
+ break;
+ case MarkType::kSet:
+ if ("sRGB" == string(iter->fContentStart,
+ iter->fContentEnd - iter->fContentStart)) {
+ srgbStr = "true";
+ } else {
+ SkASSERT(0); // more work to do
+ return false;
+ }
+ break;
+ case MarkType::kStdOut:
+ textOut = true;
+ break;
+ default:
+ SkASSERT(0); // more coding to do
+ }
+ }
+ string animatedStr = "0" != durationStr ? "true" : "false";
+ string textOutStr = textOut ? "true" : "false";
+ size_t pos = 0;
+ while (pos < text.length() && ' ' > text[pos]) {
+ ++pos;
+ }
+ size_t end = text.length();
+ size_t outIndent = 0;
+ size_t textIndent = count_indent(text, pos, end);
+ if ("" == def->fWrapper) {
+ this->setWrapper(def);
+ }
+ if (def->fWrapper.length() > 0) {
+ code += def->fWrapper;
+ code += "\\n";
+ outIndent = 4;
+ }
+ add_code(text, pos, end, outIndent, textIndent, code);
+ if (def->fWrapper.length() > 0) {
+ code += "}";
+ }
+ string example = "\"" + normalizedName + "\": {\n";
+ size_t nameStart = def->fFileName.find(SkOSPath::SEPARATOR, 0);
+ SkASSERT(string::npos != nameStart);
+ string baseFile = def->fFileName.substr(nameStart + 1, def->fFileName.length() - nameStart - 5);
+ if (ExampleOptions::kText == exampleOptions) {
+ example += " \"code\": \"" + code + "\",\n";
+ example += " \"hash\": \"" + def->fHash + "\",\n";
+ example += " \"file\": \"" + baseFile + "\",\n";
+ example += " \"name\": \"" + def->fName + "\",";
+ } else {
+ example += " \"code\": \"" + code + "\",\n";
+ if (ExampleOptions::kPng == exampleOptions) {
+ example += " \"width\": " + widthStr + ",\n";
+ example += " \"height\": " + heightStr + ",\n";
+ example += " \"hash\": \"" + def->fHash + "\",\n";
+ example += " \"file\": \"" + baseFile + "\",\n";
+ example += " \"name\": \"" + def->fName + "\"\n";
+ example += "}";
+ } else {
+ example += " \"options\": {\n";
+ example += " \"width\": " + widthStr + ",\n";
+ example += " \"height\": " + heightStr + ",\n";
+ example += " \"source\": " + imageStr + ",\n";
+ example += " \"srgb\": " + srgbStr + ",\n";
+ example += " \"f16\": false,\n";
+ example += " \"textOnly\": " + textOutStr + ",\n";
+ example += " \"animated\": " + animatedStr + ",\n";
+ example += " \"duration\": " + durationStr + "\n";
+ example += " },\n";
+ example += " \"fast\": true";
+ }
+ }
+ *result = example;
+ return true;
+}
+
+string BmhParser::extractText(const Definition* def, TrimExtract trimExtract) const {
+ string result;
+ TextParser parser(def);
+ auto childIter = def->fChildren.begin();
+ while (!parser.eof()) {
+ const char* end = def->fChildren.end() == childIter ? parser.fEnd : (*childIter)->fStart;
+ string fragment(parser.fChar, end - parser.fChar);
+ trim_end(fragment);
+ if (TrimExtract::kYes == trimExtract) {
+ trim_start(fragment);
+ if (result.length()) {
+ result += '\n';
+ result += '\n';
+ }
+ }
+ if (TrimExtract::kYes == trimExtract || has_nonwhitespace(fragment)) {
+ result += fragment;
+ }
+ parser.skipTo(end);
+ if (def->fChildren.end() != childIter) {
+ Definition* child = *childIter;
+ if (MarkType::kPhraseRef == child->fMarkType) {
+ auto phraseIter = fPhraseMap.find(child->fName);
+ if (fPhraseMap.end() == phraseIter) {
+ return def->reportError<string>("missing phrase definition");
+ }
+ Definition* phrase = phraseIter->second;
+ // count indent of last line in result
+ size_t lastLF = result.rfind('\n');
+ size_t startPos = string::npos == lastLF ? 0 : lastLF;
+ size_t lastLen = result.length() - startPos;
+ size_t indent = count_indent(result, startPos, result.length()) + 4;
+ string phraseStr = this->extractText(phrase, TrimExtract::kNo);
+ startPos = 0;
+ bool firstTime = true;
+ size_t endPos;
+ do {
+ endPos = phraseStr.find('\n', startPos);
+ size_t len = (string::npos != endPos ? endPos : phraseStr.length()) - startPos;
+ if (firstTime && lastLen + len + 1 < 100) { // FIXME: make 100 global const or something
+ result += ' ';
+ } else {
+ result += '\n';
+ result += string(indent, ' ');
+ }
+ firstTime = false;
+ string tmp = phraseStr.substr(startPos, len);
+ result += tmp;
+ startPos = endPos + 1;
+ } while (string::npos != endPos);
+ result += '\n';
+ }
+ parser.skipTo(child->fTerminator);
+ std::advance(childIter, 1);
+ }
+ }
+ return result;
+}
+
+void BmhParser::setWrapper(Definition* def) const {
+ const char drawWrapper[] = "void draw(SkCanvas* canvas) {";
+ const char drawNoCanvas[] = "void draw(SkCanvas* ) {";
+ string text = this->extractText(def, TrimExtract::kNo);
+ size_t nonSpace = 0;
+ while (nonSpace < text.length() && ' ' >= text[nonSpace]) {
+ ++nonSpace;
+ }
+ bool hasFunc = !text.compare(nonSpace, sizeof(drawWrapper) - 1, drawWrapper);
+ bool noCanvas = !text.compare(nonSpace, sizeof(drawNoCanvas) - 1, drawNoCanvas);
+ bool hasCanvas = string::npos != text.find("SkCanvas canvas");
+ SkASSERT(!hasFunc || !noCanvas);
+ bool preprocessor = text[0] == '#';
+ bool wrapCode = !hasFunc && !noCanvas && !preprocessor;
+ if (wrapCode) {
+ def->fWrapper = hasCanvas ? string(drawNoCanvas) : string(drawWrapper);
+ }
+}
+
// FIXME: some examples may produce different output on different platforms
// if the text output can be different, think of how to author that
@@ -812,7 +1087,7 @@ bool BmhParser::findDefinitions() {
if (' ' >= fMC) {
return this->reportError<bool>("illegal markup character");
}
- fMarkup.emplace_front(MarkType::kMarkChar, fChar - 1, fLineCount, fParent);
+ fMarkup.emplace_front(MarkType::kMarkChar, fChar - 4, fLineCount, fParent, fMC);
Definition* markChar = &fMarkup.front();
markChar->fContentStart = fChar - 1;
this->skipToEndBracket('\n');
@@ -865,7 +1140,7 @@ bool BmhParser::findDefinitions() {
}
} else { // one line comment
fMarkup.emplace_front(MarkType::kComment, fChar - 1, fLineCount,
- fParent);
+ fParent, fMC);
Definition* comment = &fMarkup.front();
comment->fContentStart = fChar - 1;
this->skipToEndBracket('\n');
@@ -890,7 +1165,7 @@ bool BmhParser::findDefinitions() {
} else if (TableState::kNone == fTableState) {
// fixme? no nested tables for now
fColStart = fChar - 1;
- fMarkup.emplace_front(MarkType::kRow, fColStart, fLineCount, fParent);
+ fMarkup.emplace_front(MarkType::kRow, fColStart, fLineCount, fParent, fMC);
fRow = &fMarkup.front();
fRow->fName = fParent->fName;
this->skipWhiteSpace();
@@ -899,7 +1174,7 @@ bool BmhParser::findDefinitions() {
fTableState = TableState::kColumnStart;
}
if (TableState::kColumnStart == fTableState) {
- fMarkup.emplace_front(MarkType::kColumn, fColStart, fLineCount, fParent);
+ fMarkup.emplace_front(MarkType::kColumn, fColStart, fLineCount, fParent, fMC);
fWorkingColumn = &fMarkup.front();
fWorkingColumn->fName = fParent->fName;
fWorkingColumn->fContentStart = fChar;
@@ -907,6 +1182,28 @@ bool BmhParser::findDefinitions() {
fTableState = TableState::kColumnEnd;
continue;
}
+ } else if (this->peek() >= 'a' && this->peek() <= 'z') {
+ // expect zero or more letters and underscores (no spaces) then hash
+ const char* phraseNameStart = fChar;
+ this->skipPhraseName();
+ string phraseKey = string(phraseNameStart, fChar - phraseNameStart);
+ if (fMC != this->next()) {
+ return this->reportError<bool>("expect # after phrase-name");
+ }
+ const char* start = phraseNameStart;
+ SkASSERT('#' == start[-1]);
+ --start;
+ if (start > fStart && ' ' >= start[-1]) {
+ --start; // preserve whether to add whitespace before substitution
+ }
+ fMarkup.emplace_front(MarkType::kPhraseRef, start, fLineCount, fParent, fMC);
+ Definition* markChar = &fMarkup.front();
+ markChar->fContentStart = fChar;
+ this->skipToEndBracket('\n');
+ markChar->fContentEnd = fChar;
+ markChar->fTerminator = fChar;
+ markChar->fName = phraseKey;
+ fParent->fChildren.push_back(markChar);
}
}
char nextChar = this->next();
@@ -1316,6 +1613,45 @@ const Definition* BmhParser::parentSpace() const {
return parent;
}
+const char* BmhParser::checkForFullTerminal(const char* end, const Definition* definition) const {
+ const char* start = end;
+ while ('\n' != start[0] && start > fStart) {
+ --start;
+ }
+ SkASSERT (start < end);
+ // if end is preceeeded by \n#MarkType ## backup to there
+ TextParser parser(fFileName, start, fChar, fLineCount);
+ parser.skipWhiteSpace();
+ if (parser.eof() || fMC != parser.next()) {
+ return end;
+ }
+ const char* markName = fMaps[(int) definition->fMarkType].fName;
+ if (!parser.skipExact(markName)) {
+ return end;
+ }
+ parser.skipWhiteSpace();
+ const char* nameStart = parser.fChar;
+ if (isupper(nameStart[0])) {
+ parser.skipToWhiteSpace();
+ if (parser.eof()) {
+ return end;
+ }
+ string defName = string(nameStart, parser.fChar - nameStart);
+ size_t defNamePos = definition->fName.rfind(defName);
+ if (definition->fName.length() != defNamePos + defName.length()) {
+ return end;
+ }
+ }
+ parser.skipWhiteSpace();
+ if (fMC != parser.next()) {
+ return end;
+ }
+ if (!parser.eof() && fMC != parser.next()) {
+ return end;
+ }
+ return start;
+}
+
bool BmhParser::popParentStack(Definition* definition) {
if (!fParent) {
return this->reportError<bool>("missing parent");
@@ -1329,7 +1665,19 @@ bool BmhParser::popParentStack(Definition* definition) {
if (definition->fContentEnd) {
return this->reportError<bool>("definition already ended");
}
- definition->fContentEnd = fLine - 1;
+ // more to figure out to handle table columns, at minimum
+ const char* end = fChar;
+ if (fMC != end[0]) {
+ while (end > definition->fContentStart && ' ' >= end[-1]) {
+ --end;
+ }
+ SkASSERT(&end[-1] >= definition->fContentStart && fMC == end[-1]
+ && (MarkType::kColumn == definition->fMarkType
+ || (&end[-2] >= definition->fContentStart && fMC == end[-2])));
+ end -= 2;
+ }
+ end = checkForFullTerminal(end, definition);
+ definition->fContentEnd = end;
definition->fTerminator = fChar;
fParent = definition->fParent;
if (!fParent || (MarkType::kTopic == fParent->fMarkType && !fParent->fParent)) {
@@ -1629,7 +1977,8 @@ vector<string> BmhParser::typeName(MarkType markType, bool* checkEnd) {
builder = this->typedefName();
break;
case MarkType::kParam:
- // fixme: expect camelCase
+ case MarkType::kPhraseDef:
+ // fixme: expect camelCase for param
builder = this->word("", "");
this->skipSpace();
*checkEnd = false;
diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h
index 7bb743c9cb..db0d9926db 100644
--- a/tools/bookmaker/bookmaker.h
+++ b/tools/bookmaker/bookmaker.h
@@ -120,6 +120,8 @@ enum class MarkType {
kNoExample,
kOutdent,
kParam,
+ kPhraseDef,
+ kPhraseRef,
kPlatform,
kPopulate,
kPrivate,
@@ -504,6 +506,12 @@ public:
}
}
+ void skipPhraseName() {
+ while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
+ fChar++;
+ }
+ }
+
void skipToSpace() {
while (fChar < fEnd && ' ' != fChar[0]) {
fChar++;
@@ -637,6 +645,17 @@ public:
return fChar + index;
}
+ const char* trimmedBracketEnd(string bracket) const {
+ size_t max = (size_t) (this->lineLength());
+ string line(fChar, max);
+ size_t index = line.find(bracket);
+ SkASSERT(index < max);
+ while (index > 0 && ' ' >= fChar[index - 1]) {
+ --index;
+ }
+ return fChar + index;
+ }
+
const char* trimmedLineEnd() const {
const char* result = this->lineEnd();
while (result > fChar && ' ' >= result[-1]) {
@@ -730,17 +749,6 @@ public:
kFileType,
};
- enum class TrimExtract {
- kNo,
- kYes
- };
-
- enum class ExampleOptions {
- kText,
- kPng,
- kAll
- };
-
enum class MethodType {
kNone,
kConstructor,
@@ -775,13 +783,14 @@ public:
Definition() {}
- Definition(const char* start, const char* end, int line, Definition* parent)
+ Definition(const char* start, const char* end, int line, Definition* parent, char mc)
: fStart(start)
, fContentStart(start)
, fContentEnd(end)
, fParent(parent)
, fLineCount(line)
- , fType(Type::kWord) {
+ , fType(Type::kWord)
+ , fMC(mc) {
if (parent) {
SkASSERT(parent->fFileName.length() > 0);
fFileName = parent->fFileName;
@@ -789,31 +798,31 @@ public:
this->setParentIndex();
}
- Definition(MarkType markType, const char* start, int line, Definition* parent)
- : Definition(markType, start, nullptr, line, parent) {
+ Definition(MarkType markType, const char* start, int line, Definition* parent, char mc)
+ : Definition(markType, start, nullptr, line, parent, mc) {
}
- Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent)
- : Definition(start, end, line, parent) {
+ Definition(MarkType markType, const char* start, const char* end, int line, Definition* parent, char mc)
+ : Definition(start, end, line, parent, mc) {
fMarkType = markType;
fType = Type::kMark;
}
- Definition(Bracket bracket, const char* start, int lineCount, Definition* parent)
- : Definition(start, nullptr, lineCount, parent) {
+ Definition(Bracket bracket, const char* start, int lineCount, Definition* parent, char mc)
+ : Definition(start, nullptr, lineCount, parent, mc) {
fBracket = bracket;
fType = Type::kBracket;
}
Definition(KeyWord keyWord, const char* start, const char* end, int lineCount,
- Definition* parent)
- : Definition(start, end, lineCount, parent) {
+ Definition* parent, char mc)
+ : Definition(start, end, lineCount, parent, mc) {
fKeyWord = keyWord;
fType = Type::kKeyWord;
}
- Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent)
- : Definition(start, nullptr, lineCount, parent) {
+ Definition(Punctuation punctuation, const char* start, int lineCount, Definition* parent, char mc)
+ : Definition(start, nullptr, lineCount, parent, mc) {
fPunctuation = punctuation;
fType = Type::kPunctuation;
}
@@ -845,8 +854,6 @@ public:
return nullptr;
}
- bool exampleToScript(string* result, ExampleOptions ) const;
- string extractText(TrimExtract trimExtract) const;
string fiddleName() const;
const Definition* findClone(string match) const;
string formatFunction(Format format) const;
@@ -901,8 +908,6 @@ public:
fParentIndex = fParent ? (int) fParent->fTokens.size() : -1;
}
- void setWrapper();
-
const Definition* topicParent() const {
Definition* test = fParent;
while (test) {
@@ -936,6 +941,7 @@ public:
MethodType fMethodType = MethodType::kNone;
Operator fOperator = Operator::kUnknown;
Type fType = Type::kNone;
+ char fMC = '#';
bool fClone = false;
bool fCloned = false;
bool fDeprecated = false;
@@ -958,12 +964,12 @@ public:
RootDefinition() {
}
- RootDefinition(MarkType markType, const char* start, int line, Definition* parent)
- : Definition(markType, start, line, parent) {
+ RootDefinition(MarkType markType, const char* start, int line, Definition* parent, char mc)
+ : Definition(markType, start, line, parent, mc) {
}
RootDefinition(MarkType markType, const char* start, const char* end, int line,
- Definition* parent) : Definition(markType, start, end, line, parent) {
+ Definition* parent, char mc) : Definition(markType, start, end, line, parent, mc) {
}
~RootDefinition() override {
@@ -1205,6 +1211,12 @@ public:
kClone, // resolved, output, with references to clones as well
};
+ enum class ExampleOptions {
+ kText,
+ kPng,
+ kAll
+ };
+
enum class Exemplary {
kNo,
kYes,
@@ -1222,6 +1234,11 @@ public:
kYes,
};
+ enum class TrimExtract {
+ kNo,
+ kYes
+ };
+
#define M(mt) (1LL << (int) MarkType::k##mt)
#define M_D M(Description)
#define M_CS M(Class) | M(Struct)
@@ -1287,6 +1304,8 @@ public:
, { "NoExample", nullptr, MarkType::kNoExample, R_O, E_N, M_CSST | M_E | M(Method) }
, { "Outdent", nullptr, MarkType::kOutdent, R_N, E_N, M(Code) }
, { "Param", nullptr, MarkType::kParam, R_Y, E_N, M(Method) }
+, { "PhraseDef", nullptr, MarkType::kPhraseDef, R_Y, E_N, M(Subtopic) }
+, { "", nullptr, MarkType::kPhraseRef, R_Y, E_N, 0 }
, { "Platform", nullptr, MarkType::kPlatform, R_N, E_N, M(Example) | M(NoExample) }
, { "Populate", nullptr, MarkType::kPopulate, R_N, E_N, M(Subtopic) }
, { "Private", nullptr, MarkType::kPrivate, R_N, E_N, 0 }
@@ -1333,13 +1352,17 @@ public:
const vector<string>& typeNameBuilder, HasTag hasTag);
bool checkEndMarker(MarkType markType, string name) const;
bool checkExamples() const;
+ const char* checkForFullTerminal(const char* end, const Definition* ) const;
bool checkParamReturn(const Definition* definition) const;
+ bool dumpExamples(FILE* fiddleOut, Definition& def, bool* continuation) const;
bool dumpExamples(const char* fiddleJsonFileName) const;
bool childOf(MarkType markType) const;
string className(MarkType markType);
bool collectExternals();
int endHashCount() const;
bool endTableColumn(const char* end, const char* terminator);
+ bool exampleToScript(Definition*, ExampleOptions, string* result ) const;
+ string extractText(const Definition* , TrimExtract ) const;
RootDefinition* findBmhObject(MarkType markType, const string& typeName) const {
auto map = fMaps[(int) markType].fBmh;
@@ -1383,6 +1406,7 @@ public:
fCheckMethods = false;
}
+ void setWrapper(Definition* def) const;
bool skipNoName();
bool skipToDefinitionEnd(MarkType markType);
bool skipToString();
@@ -1418,6 +1442,7 @@ public:
unordered_map<string, RootDefinition> fTypedefMap;
unordered_map<string, Definition*> fTopicMap;
unordered_map<string, Definition*> fAliasMap;
+ unordered_map<string, Definition*> fPhraseMap;
RootDefinition* fRoot;
Definition* fWorkingColumn;
Definition* fRow;
@@ -1485,6 +1510,8 @@ public:
, { nullptr, MarkType::kNoExample }
, { nullptr, MarkType::kOutdent }
, { nullptr, MarkType::kParam }
+ , { nullptr, MarkType::kPhraseDef }
+ , { nullptr, MarkType::kPhraseRef }
, { nullptr, MarkType::kPlatform }
, { nullptr, MarkType::kPopulate }
, { nullptr, MarkType::kPrivate }
@@ -1517,11 +1544,11 @@ public:
void addKeyword(KeyWord keyWord);
void addPunctuation(Punctuation punctuation) {
- fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent);
+ fParent->fTokens.emplace_back(punctuation, fChar, fLineCount, fParent, '\0');
}
void addWord() {
- fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent);
+ fParent->fTokens.emplace_back(fIncludeWord, fChar, fLineCount, fParent, '\0');
fIncludeWord = nullptr;
}
@@ -1602,7 +1629,7 @@ public:
void pushBracket(Bracket bracket) {
this->setBracketShortCuts(bracket);
- fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent);
+ fParent->fTokens.emplace_back(bracket, fChar, fLineCount, fParent, '\0');
Definition* container = &fParent->fTokens.back();
this->addDefinition(container);
}
@@ -1889,7 +1916,7 @@ public:
void constOut(const Definition* memberStart, const Definition& child,
const Definition* bmhConst);
- void descriptionOut(const Definition* def, SkipFirstLine );
+ void descriptionOut(const Definition* def, SkipFirstLine , Phrase );
void enumHeaderOut(const RootDefinition* root, const Definition& child);
void enumMembersOut(const RootDefinition* root, Definition& child);
void enumSizeItems(const Definition& child);
diff --git a/tools/bookmaker/cataloger.cpp b/tools/bookmaker/cataloger.cpp
index b3f578dd71..a564d3ee98 100644
--- a/tools/bookmaker/cataloger.cpp
+++ b/tools/bookmaker/cataloger.cpp
@@ -103,7 +103,7 @@ bool Catalog::parseFromFile(const char* path) {
bool Catalog::pngOut(Definition* example) {
string result;
- if (!example->exampleToScript(&result, Definition::ExampleOptions::kPng)) {
+ if (!fBmhParser->exampleToScript(example, BmhParser::ExampleOptions::kPng, &result)) {
return false;
}
if (result.length() > 0) {
@@ -121,7 +121,7 @@ bool Catalog::pngOut(Definition* example) {
bool Catalog::textOut(Definition* def, const char* stdOutStart,
const char* stdOutEnd) {
string result;
- if (!def->exampleToScript(&result, Definition::ExampleOptions::kText)) {
+ if (!fBmhParser->exampleToScript(def, BmhParser::ExampleOptions::kText, &result)) {
return false;
}
if (result.length() > 0) {
diff --git a/tools/bookmaker/definition.cpp b/tools/bookmaker/definition.cpp
index 68e001aebb..14f6daab81 100644
--- a/tools/bookmaker/definition.cpp
+++ b/tools/bookmaker/definition.cpp
@@ -6,51 +6,6 @@
*/
#include "bookmaker.h"
-#include "SkOSPath.h"
-
-static size_t count_indent(const string& text, size_t test, size_t end) {
- size_t result = test;
- while (test < end) {
- if (' ' != text[test]) {
- break;
- }
- ++test;
- }
- return test - result;
-}
-
-static void add_code(const string& text, int pos, int end,
- size_t outIndent, size_t textIndent, string& example) {
- do {
- // fix this to move whole paragraph in, out, but preserve doc indent
- int nextIndent = count_indent(text, pos, end);
- size_t len = text.find('\n', pos);
- if (string::npos == len) {
- len = end;
- }
- if ((size_t) (pos + nextIndent) < len) {
- size_t indent = outIndent + nextIndent;
- SkASSERT(indent >= textIndent);
- indent -= textIndent;
- for (size_t index = 0; index < indent; ++index) {
- example += ' ';
- }
- pos += nextIndent;
- while ((size_t) pos < len) {
- example += '"' == text[pos] ? "\\\"" :
- '\\' == text[pos] ? "\\\\" :
- text.substr(pos, 1);
- ++pos;
- }
- example += "\\n";
- } else {
- pos += nextIndent;
- }
- if ('\n' == text[pos]) {
- ++pos;
- }
- } while (pos < end);
-}
#ifdef CONST
#undef CONST
@@ -487,215 +442,6 @@ void Definition::setCanonicalFiddle() {
fFiddle = Definition::NormalizedName(result);
}
-void Definition::setWrapper() {
- const char drawWrapper[] = "void draw(SkCanvas* canvas) {";
- const char drawNoCanvas[] = "void draw(SkCanvas* ) {";
- string text = this->extractText(Definition::TrimExtract::kNo);
- size_t nonSpace = 0;
- while (nonSpace < text.length() && ' ' >= text[nonSpace]) {
- ++nonSpace;
- }
- bool hasFunc = !text.compare(nonSpace, sizeof(drawWrapper) - 1, drawWrapper);
- bool noCanvas = !text.compare(nonSpace, sizeof(drawNoCanvas) - 1, drawNoCanvas);
- bool hasCanvas = string::npos != text.find("SkCanvas canvas");
- SkASSERT(!hasFunc || !noCanvas);
- bool preprocessor = text[0] == '#';
- bool wrapCode = !hasFunc && !noCanvas && !preprocessor;
- if (wrapCode) {
- fWrapper = hasCanvas ? string(drawNoCanvas) : string(drawWrapper);
- }
-}
-
-bool Definition::exampleToScript(string* result, ExampleOptions exampleOptions) const {
- bool hasFiddle = true;
- const Definition* platform = this->hasChild(MarkType::kPlatform);
- if (platform) {
- TextParser platParse(platform);
- hasFiddle = !platParse.strnstr("!fiddle", platParse.fEnd);
- }
- if (!hasFiddle) {
- *result = "";
- return true;
- }
- string text = this->extractText(Definition::TrimExtract::kNo);
- bool textOut = string::npos != text.find("SkDebugf(")
- || string::npos != text.find("dump(")
- || string::npos != text.find("dumpHex(");
- string heightStr = "256";
- string widthStr = "256";
- string normalizedName(fFiddle);
- string code;
- string imageStr = "0";
- string srgbStr = "false";
- string durationStr = "0";
- for (auto const& iter : fChildren) {
- switch (iter->fMarkType) {
- case MarkType::kDuration:
- durationStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
- break;
- case MarkType::kHeight:
- heightStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
- break;
- case MarkType::kWidth:
- widthStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
- break;
- case MarkType::kDescription:
- // ignore for now
- break;
- case MarkType::kFunction: {
- // emit this, but don't wrap this in draw()
- string funcText(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
- size_t pos = 0;
- while (pos < funcText.length() && ' ' > funcText[pos]) {
- ++pos;
- }
- size_t indent = count_indent(funcText, pos, funcText.length());
- add_code(funcText, pos, funcText.length(), 0, indent, code);
- code += "\\n";
- } break;
- case MarkType::kComment:
- break;
- case MarkType::kImage:
- imageStr = string(iter->fContentStart, iter->fContentEnd - iter->fContentStart);
- break;
- case MarkType::kToDo:
- break;
- case MarkType::kBug:
- case MarkType::kMarkChar:
- case MarkType::kPlatform:
- // ignore for now
- break;
- case MarkType::kSet:
- if ("sRGB" == string(iter->fContentStart,
- iter->fContentEnd - iter->fContentStart)) {
- srgbStr = "true";
- } else {
- SkASSERT(0); // more work to do
- return false;
- }
- break;
- case MarkType::kStdOut:
- textOut = true;
- break;
- default:
- SkASSERT(0); // more coding to do
- }
- }
- string animatedStr = "0" != durationStr ? "true" : "false";
- string textOutStr = textOut ? "true" : "false";
- size_t pos = 0;
- while (pos < text.length() && ' ' > text[pos]) {
- ++pos;
- }
- size_t end = text.length();
- size_t outIndent = 0;
- size_t textIndent = count_indent(text, pos, end);
- if (fWrapper.length() > 0) {
- code += fWrapper;
- code += "\\n";
- outIndent = 4;
- }
- add_code(text, pos, end, outIndent, textIndent, code);
- if (fWrapper.length() > 0) {
- code += "}";
- }
- string example = "\"" + normalizedName + "\": {\n";
- size_t nameStart = fFileName.find(SkOSPath::SEPARATOR, 0);
- SkASSERT(string::npos != nameStart);
- string baseFile = fFileName.substr(nameStart + 1, fFileName.length() - nameStart - 5);
- if (ExampleOptions::kText == exampleOptions) {
- example += " \"code\": \"" + code + "\",\n";
- example += " \"hash\": \"" + fHash + "\",\n";
- example += " \"file\": \"" + baseFile + "\",\n";
- example += " \"name\": \"" + fName + "\",";
- } else {
- example += " \"code\": \"" + code + "\",\n";
- if (ExampleOptions::kPng == exampleOptions) {
- example += " \"width\": " + widthStr + ",\n";
- example += " \"height\": " + heightStr + ",\n";
- example += " \"hash\": \"" + fHash + "\",\n";
- example += " \"file\": \"" + baseFile + "\",\n";
- example += " \"name\": \"" + fName + "\"\n";
- example += "}";
- } else {
- example += " \"options\": {\n";
- example += " \"width\": " + widthStr + ",\n";
- example += " \"height\": " + heightStr + ",\n";
- example += " \"source\": " + imageStr + ",\n";
- example += " \"srgb\": " + srgbStr + ",\n";
- example += " \"f16\": false,\n";
- example += " \"textOnly\": " + textOutStr + ",\n";
- example += " \"animated\": " + animatedStr + ",\n";
- example += " \"duration\": " + durationStr + "\n";
- example += " },\n";
- example += " \"fast\": true";
- }
- }
- *result = example;
- return true;
-}
-
-string Definition::extractText(TrimExtract trimExtract) const {
- string result;
- TextParser parser(fFileName, fContentStart, fContentEnd, fLineCount);
- int childIndex = 0;
- char mc = '#';
- while (parser.fChar < parser.fEnd) {
- if (TrimExtract::kYes == trimExtract && !parser.skipWhiteSpace()) {
- break;
- }
- if (parser.next() == mc) {
- if (parser.next() == mc) {
- if (parser.next() == mc) {
- mc = parser.next();
- }
- } else {
- // fixme : more work to do if # style comment is in text
- // if in method definition, could be alternate method name
- --parser.fChar;
- if (' ' < parser.fChar[0]) {
- if (islower(parser.fChar[0])) {
- result += '\n';
- parser.skipLine();
- } else {
- SkASSERT(isupper(parser.fChar[0]));
- parser.skipTo(fChildren[childIndex]->fTerminator);
- if (mc == parser.fChar[0] && mc == parser.fChar[1]) {
- parser.next();
- parser.next();
- }
- childIndex++;
- }
- } else {
- parser.skipLine();
- }
- continue;
- }
- } else {
- --parser.fChar;
- }
- const char* end = parser.fEnd;
- const char* mark = parser.strnchr(mc, end);
- if (mark) {
- end = mark;
- }
- string fragment(parser.fChar, end - parser.fChar);
- trim_end(fragment);
- if (TrimExtract::kYes == trimExtract) {
- trim_start(fragment);
- if (result.length()) {
- result += '\n';
- result += '\n';
- }
- }
- if (TrimExtract::kYes == trimExtract || has_nonwhitespace(fragment)) {
- result += fragment;
- }
- parser.skipTo(end);
- }
- return result;
-}
-
static void space_pad(string* str) {
size_t len = str->length();
if (len == 0) {
diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp
index 385b9c92da..07189dcc3f 100644
--- a/tools/bookmaker/includeParser.cpp
+++ b/tools/bookmaker/includeParser.cpp
@@ -87,7 +87,7 @@ void IncludeParser::ValidateKeyWords() {
}
void IncludeParser::addKeyword(KeyWord keyWord) {
- fParent->fTokens.emplace_back(keyWord, fIncludeWord, fChar, fLineCount, fParent);
+ fParent->fTokens.emplace_back(keyWord, fIncludeWord, fChar, fLineCount, fParent, '\0');
fIncludeWord = nullptr;
if (KeyProperty::kObject == kKeyWords[(int) keyWord].fProperty) {
Definition* def = &fParent->fTokens.back();
@@ -1295,7 +1295,7 @@ bool IncludeParser::parseComment(const string& filename, const char* start, cons
}
const char* lineEnd = parser.trimmedLineEnd();
markupDef->fTokens.emplace_back(MarkType::kComment, parser.fChar, lineEnd,
- parser.fLineCount, parent);
+ parser.fLineCount, parent, '\0');
parser.skipToEndBracket('\n');
}
return true;
@@ -1338,7 +1338,7 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) {
markupChild->fLineCount = child->fLineCount;
} else {
markupDef->fTokens.emplace_back(MarkType::kEnum, child->fContentStart, child->fContentEnd,
- child->fLineCount, markupDef);
+ child->fLineCount, markupDef, '\0');
markupChild = &markupDef->fTokens.back();
}
SkASSERT(KeyWord::kNone == markupChild->fKeyWord);
@@ -1385,7 +1385,7 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) {
parser.skipToLineStart();
}
markupChild->fTokens.emplace_back(MarkType::kComment, start, end, parser.fLineCount,
- markupChild);
+ markupChild, '\0');
comment = &markupChild->fTokens.back();
comment->fTerminator = end;
if (!this->parseComment(parser.fFileName, start, end, parser.fLineCount, comment)) {
@@ -1439,12 +1439,12 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) {
SkASSERT(!parser.eof());
const char* commentEnd = parser.fChar;
markupChild->fTokens.emplace_back(MarkType::kComment, commentStart, commentEnd,
- parser.fLineCount, markupChild);
+ parser.fLineCount, markupChild, '\0');
comment = &markupChild->fTokens.back();
comment->fTerminator = commentEnd;
}
markupChild->fTokens.emplace_back(MarkType::kMember, dataStart, dataEnd, parser.fLineCount,
- markupChild);
+ markupChild, '\0');
Definition* member = &markupChild->fTokens.back();
member->fName = memberName;
if (comment) {
@@ -1463,7 +1463,7 @@ bool IncludeParser::parseEnum(Definition* child, Definition* markupDef) {
}
SkASSERT(KeyWord::kStatic == outsideMember->fKeyWord);
markupChild->fTokens.emplace_back(MarkType::kMember, outsideMember->fContentStart,
- outsideMember->fContentEnd, outsideMember->fLineCount, markupChild);
+ outsideMember->fContentEnd, outsideMember->fLineCount, markupChild, '\0');
Definition* member = &markupChild->fTokens.back();
member->fName = outsideMember->fName;
// FIXME: ? add comment as well ?
@@ -1503,7 +1503,7 @@ bool IncludeParser::parseInclude(const string& name) {
bool IncludeParser::parseMember(Definition* child, Definition* markupDef) {
const char* typeStart = child->fChildren[0]->fContentStart;
markupDef->fTokens.emplace_back(MarkType::kMember, typeStart, child->fContentStart,
- child->fLineCount, markupDef);
+ child->fLineCount, markupDef, '\0');
Definition* markupChild = &markupDef->fTokens.back();
TextParser nameParser(child);
nameParser.skipToNonAlphaNum();
@@ -1534,7 +1534,7 @@ bool IncludeParser::parseMember(Definition* child, Definition* markupDef) {
}
}
markupDef->fTokens.emplace_back(MarkType::kComment, start, end, child->fLineCount,
- markupDef);
+ markupDef, '\0');
Definition* commentChild = &markupDef->fTokens.back();
markupChild->fChildren.emplace_back(commentChild);
parser.skipTo(end);
@@ -1676,7 +1676,7 @@ bool IncludeParser::parseMethod(Definition* child, Definition* markupDef) {
return true;
}
markupDef->fTokens.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount,
- markupDef);
+ markupDef, '\0');
Definition* markupChild = &markupDef->fTokens.back();
// do find instead -- I wonder if there is a way to prevent this in c++
IClassDefinition& classDef = fIClassMap[markupDef->fName];
@@ -1873,7 +1873,7 @@ bool IncludeParser::parseTypedef(Definition* child, Definition* markupDef) {
return true;
}
markupDef->fTokens.emplace_back(MarkType::kTypedef, child->fContentStart, child->fContentEnd,
- child->fLineCount, markupDef);
+ child->fLineCount, markupDef, '\0');
Definition* markupChild = &markupDef->fTokens.back();
markupChild->fName = nameStr;
markupChild->fTerminator = markupChild->fContentEnd;
diff --git a/tools/bookmaker/includeWriter.cpp b/tools/bookmaker/includeWriter.cpp
index 328e9412cb..83895ea78a 100644
--- a/tools/bookmaker/includeWriter.cpp
+++ b/tools/bookmaker/includeWriter.cpp
@@ -15,13 +15,14 @@ void IncludeWriter::constOut(const Definition* memberStart, const Definition& ch
this->lf(2);
this->writeCommentHeader();
fIndent += 4;
- this->descriptionOut(bmhConst, SkipFirstLine::kYes);
+ this->descriptionOut(bmhConst, SkipFirstLine::kYes, Phrase::kNo);
fIndent -= 4;
this->writeCommentTrailer();
fStart = memberStart->fContentStart;
}
-void IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirstLine) {
+void IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirstLine,
+ Phrase phrase) {
const char* commentStart = def->fContentStart;
if (SkipFirstLine::kYes == skipFirstLine) {
TextParser parser(def);
@@ -99,7 +100,11 @@ void IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirs
commentLen = (int) (prop->fContentEnd - commentStart);
if (commentLen > 0) {
this->writeBlockIndent(commentLen, commentStart);
- if ('\n' != commentStart[commentLen - 1] && '\n' == commentStart[commentLen]) {
+ const char* end = commentStart + commentLen;
+ while (end > commentStart && ' ' == end[-1]) {
+ --end;
+ }
+ if (end > commentStart && '\n' == end[-1]) {
this->lfcr();
}
}
@@ -175,7 +180,7 @@ void IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirs
SkASSERT(MarkType::kColumn == column->fMarkType);
this->writeString("-");
this->writeSpace();
- this->descriptionOut(column, SkipFirstLine::kNo);
+ this->descriptionOut(column, SkipFirstLine::kNo, Phrase::kNo);
this->lf(1);
}
}
@@ -185,6 +190,22 @@ void IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirs
this->lf(2);
}
break;
+ case MarkType::kPhraseRef: {
+ commentLen = prop->fStart - commentStart;
+ if (commentLen > 0) {
+ this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
+ // ince we don't do line wrapping, always insert LF before phrase
+ this->lfcr(); // TODO: remove this once rewriteBlock rewraps paragraphs
+ }
+ auto iter = fBmhParser->fPhraseMap.find(prop->fName);
+ if (fBmhParser->fPhraseMap.end() == iter) {
+ return this->reportError<void>("missing phrase definition");
+ }
+ Definition* phraseDef = iter->second;
+ this->rewriteBlock(phraseDef->length(), phraseDef->fContentStart, Phrase::kYes);
+ commentStart = prop->fContentStart;
+ commentLen = (int) (def->fContentEnd - commentStart);
+ } break;
default:
commentLen = (int) (prop->fStart - commentStart);
breakOut = true;
@@ -195,7 +216,7 @@ void IncludeWriter::descriptionOut(const Definition* def, SkipFirstLine skipFirs
}
SkASSERT(wroteCode || (commentLen > 0 && commentLen < 1500) || def->fDeprecated);
if (commentLen > 0) {
- this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
+ this->rewriteBlock(commentLen, commentStart, phrase);
}
}
@@ -654,7 +675,7 @@ void IncludeWriter::methodOut(const Definition* method, const Definition& child)
}
this->writeCommentHeader();
fIndent += 4;
- this->descriptionOut(method, SkipFirstLine::kNo);
+ this->descriptionOut(method, SkipFirstLine::kNo, Phrase::kNo);
// compute indention column
size_t column = 0;
bool hasParmReturn = false;
@@ -671,8 +692,6 @@ void IncludeWriter::methodOut(const Definition* method, const Definition& child)
column += fIndent + sizeof("@return ");
int saveIndent = fIndent;
for (auto methodPart : method->fChildren) {
- const char* partStart = methodPart->fContentStart;
- const char* partEnd = methodPart->fContentEnd;
if (MarkType::kParam == methodPart->fMarkType) {
this->writeString("@param");
this->writeSpace();
@@ -682,18 +701,24 @@ void IncludeWriter::methodOut(const Definition* method, const Definition& child)
} else {
continue;
}
+ this->indentToColumn(column);
+ fIndent = column;
+#if 0
+ const char* partStart = methodPart->fContentStart;
+ const char* partEnd = methodPart->fContentEnd;
while ('\n' == partEnd[-1]) {
--partEnd;
}
while ('#' == partEnd[-1]) { // FIXME: so wrong; should not be before fContentEnd
--partEnd;
}
- this->indentToColumn(column);
int partLen = (int) (partEnd - partStart);
// FIXME : detect this earlier; assert if #Return is empty
SkASSERT(partLen > 0 && partLen < 300); // may assert if param desc is especially long
- fIndent = column;
this->rewriteBlock(partLen, partStart, Phrase::kYes);
+#else
+ this->descriptionOut(methodPart, SkipFirstLine::kNo, Phrase::kYes);
+#endif
fIndent = saveIndent;
this->lfcr();
}
@@ -820,7 +845,7 @@ Definition* IncludeWriter::structMemberOut(const Definition* memberStart, const
this->indentToColumn(fStructCommentTab);
this->writeString("//!<");
this->writeSpace();
- string extract = commentBlock->extractText(Definition::TrimExtract::kYes);
+ string extract = fBmhParser->extractText(commentBlock, BmhParser::TrimExtract::kYes);
this->rewriteBlock(extract.length(), &extract.front(), Phrase::kNo);
}
this->lf(2);
@@ -833,7 +858,7 @@ void IncludeWriter::structSetMembersShort(const vector<Definition*>& bmhChildren
if (MarkType::kMember != memberDef->fMarkType) {
continue;
}
- string extract = memberDef->extractText(Definition::TrimExtract::kYes);
+ string extract = fBmhParser->extractText(memberDef, BmhParser::TrimExtract::kYes);
bool multiline = string::npos != extract.find('\n');
if (multiline) {
memberDef->fShort = false;
diff --git a/tools/bookmaker/mdOut.cpp b/tools/bookmaker/mdOut.cpp
index f74853b470..ff1bff2634 100644
--- a/tools/bookmaker/mdOut.cpp
+++ b/tools/bookmaker/mdOut.cpp
@@ -166,7 +166,9 @@ string MdOut::addReferences(const char* refStart, const char* refEnd,
// look for Sk / sk / SK ..
if (!ref.compare(0, 2, "Sk") && ref != "Skew" && ref != "Skews" &&
ref != "Skip" && ref != "Skips") {
- t.reportError("missed Sk prefixed");
+ if (BmhParser::Resolvable::kOut != resolvable) {
+ t.reportError("missed Sk prefixed");
+ }
return result;
}
if (!ref.compare(0, 2, "SK")) {
@@ -744,7 +746,9 @@ void MdOut::markTypeOut(Definition* def) {
const char* textStart = def->fContentStart;
if (MarkType::kParam != def->fMarkType && MarkType::kConst != def->fMarkType &&
(!def->fParent || MarkType::kConst != def->fParent->fMarkType) &&
- TableState::kNone != fTableState) {
+ TableState::kNone != fTableState &&
+ (MarkType::kPhraseRef != def->fMarkType || !def->fParent ||
+ MarkType::kParam != def->fParent->fMarkType)) {
this->writePending();
FPRINTF("</table>");
this->lf(2);
@@ -1088,6 +1092,22 @@ void MdOut::markTypeOut(Definition* def) {
break;
case MarkType::kWidth:
break;
+ case MarkType::kPhraseDef:
+ break;
+ case MarkType::kPhraseRef:
+ if (fBmhParser.fPhraseMap.end() == fBmhParser.fPhraseMap.find(def->fName)) {
+ def->reportError<void>("missing phrase definition");
+ } else {
+ if (fColumn && ' ' >= def->fStart[0]) {
+ this->writeSpace();
+ }
+ Definition* phraseRef = fBmhParser.fPhraseMap.find(def->fName)->second;
+ this->childrenOut(phraseRef, phraseRef->fContentStart);
+ if (' ' >= def->fContentStart[0]) {
+ this->writeSpace();
+ }
+ }
+ break;
default:
SkDebugf("fatal error: MarkType::k%s unhandled in %s()\n",
fBmhParser.fMaps[(int) def->fMarkType].fName, __func__);
@@ -1195,6 +1215,8 @@ void MdOut::markTypeOut(Definition* def) {
case MarkType::kTable:
this->lf(2);
break;
+ case MarkType::kPhraseDef:
+ break;
case MarkType::kPrivate:
break;
default: