Check every word in docs
This enables checking all text to see if it
either represents a valid reference or is a
word in docs/spelling.txt . Expressions are
checked for validity as well.
There are a few shortcuts (marked with TODO):
- typedefs aren't resolved, so cheats are
added for SkVector and SkIVector.
- operator overload detection is incomplete
- constructor detection is incomplete
- formula definitions aren't detected
Found and fixed a bunch of spelling, usage,
and incorrect or obsolete references.
A few comment changes are needed in
include/core to get this to work, mostly
centered around recent SkPaint/SkFont edits.
TBR=reed@google.com
Docs-Preview: https://skia.org/?cl=167541
Bug: skia:
Change-Id: I2e0d5990105c5a8482b0c0d3e50fd0b330996dd6
Reviewed-on: https://skia-review.googlesource.com/c/167541
Reviewed-by: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/bmhParser.cpp b/tools/bookmaker/bmhParser.cpp
index bfdffc7..a0a46c3 100644
--- a/tools/bookmaker/bmhParser.cpp
+++ b/tools/bookmaker/bmhParser.cpp
@@ -294,6 +294,7 @@
definition->fFiddle = parent->fFiddle + '_';
}
rootDefinition->fNames.fName = rootDefinition->fName;
+ rootDefinition->fNames.fParent = &fGlobalNames;
definition->fFiddle += Definition::NormalizedName(typeNameBuilder[0]);
this->setAsParent(definition);
}
@@ -1281,13 +1282,21 @@
fclose(file);
int i = 0;
int start = i;
+ string last = " ";
string word;
do {
if (' ' < buffer[i]) {
++i;
continue;
}
+ last = word;
word = string(&buffer[start], i - start);
+#ifdef SK_DEBUG
+ SkASSERT(last.compare(word) < 0);
+ for (char c : word) {
+ SkASSERT(islower(c) || '-' == c);
+ }
+#endif
if (fGlobalNames.fRefMap.end() == fGlobalNames.fRefMap.find(word)) {
fGlobalNames.fRefMap[word] = nullptr;
} else {
@@ -1320,23 +1329,14 @@
continue;
}
}
- size_t lastUnder = name.rfind('_');
- if (string::npos != lastUnder && ++lastUnder < name.length()) {
- bool numbers = true;
- for (size_t index = lastUnder; index < name.length(); ++index) {
- numbers &= (bool) isdigit(name[index]);
- }
- if (numbers) {
- continue;
- }
- }
string ref;
if (&fGlobalNames == names) {
ref = ParserCommon::HtmlFileName(child->fFileName);
}
ref += '#' + child->fFiddle;
if (MarkType::kClass == markType || MarkType::kStruct == markType
- || MarkType::kMethod == markType || MarkType::kEnum == markType
+ || (MarkType::kMethod == markType && !child->fClone)
+ || MarkType::kEnum == markType
|| MarkType::kEnumClass == markType || MarkType::kConst == markType
|| MarkType::kMember == markType || MarkType::kDefine == markType
|| MarkType::kTypedef == markType) {
@@ -1355,6 +1355,28 @@
if (MarkType::kEnum == markType) {
this->setUpSubstitutes(child, names);
}
+ if (MarkType::kMethod == markType) {
+ if (child->fClone || child->fCloned) {
+ TextParser parser(child->fFileName, child->fStart, child->fContentStart,
+ child->fLineCount);
+ parser.skipExact("#Method");
+ parser.skipSpace();
+ string name = child->methodName();
+ const char* nameInParser = parser.strnstr(name.c_str(), parser.fEnd);
+ parser.skipTo(nameInParser);
+ const char* paren = parser.strnchr('(', parser.fEnd);
+ parser.skipTo(paren);
+ parser.skipToBalancedEndBracket('(', ')');
+ if ("()" != string(paren, parser.fChar - paren)) {
+ string fullName =
+ trim_inline_spaces(string(nameInParser, parser.fChar - nameInParser));
+ SkASSERT(names->fLinkMap.end() == names->fLinkMap.find(fullName));
+ names->fLinkMap[fullName] = ref;
+ SkASSERT(names->fRefMap.end() == names->fRefMap.find(fullName));
+ names->fRefMap[fullName] = child;
+ }
+ }
+ }
if (MarkType::kSubtopic == markType) {
if (&fGlobalNames != names && string::npos != child->fName.find('_')) {
string lowered = this->loweredTopic(child->fName, child);
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index bbbcb1b..ab9b943 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -373,3 +373,38 @@
}
}
}
+
+void NameMap::setParams(Definition* bmhDef, Definition* iMethod) {
+ Definition* pParent = bmhDef->csParent();
+ string parentName;
+ if (pParent) {
+ parentName = pParent->fName + "::";
+ fParent = &pParent->asRoot()->fNames;
+ }
+ fName = parentName + iMethod->fName;
+ TextParser methParams(iMethod);
+ for (auto& param : iMethod->fTokens) {
+ if (MarkType::kComment != param.fMarkType) {
+ continue;
+ }
+ TextParser paramParser(¶m);
+ if (!paramParser.skipExact("@param ")) { // write parameters, if any
+ continue;
+ }
+ paramParser.skipSpace();
+ const char* start = paramParser.fChar;
+ paramParser.skipToSpace();
+ string paramName(start, paramParser.fChar - start);
+ #ifdef SK_DEBUG
+ for (char c : paramName) {
+ SkASSERT(isalnum(c) || '_' == c);
+ }
+ #endif
+ if (!methParams.containsWord(paramName.c_str(), methParams.fEnd, nullptr)) {
+ param.reportError<void>("mismatched param name");
+ }
+ fRefMap[paramName] = ¶m;
+ fLinkMap[paramName] = '#' + bmhDef->fFiddle + '_' + paramName;
+ }
+}
+
diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h
index 59083a7..4fb65ca 100644
--- a/tools/bookmaker/bookmaker.h
+++ b/tools/bookmaker/bookmaker.h
@@ -215,6 +215,7 @@
struct NameMap {
void copyToParent(NameMap* parent) const;
+ void setParams(Definition* bmhDef, Definition* iMethod);
string fName;
NameMap* fParent = nullptr;
diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp
index 5662bcf..523a3e8 100644
--- a/tools/bookmaker/includeParser.cpp
+++ b/tools/bookmaker/includeParser.cpp
@@ -1854,6 +1854,10 @@
}
Definition* IncludeParser::findMethod(const Definition& bmhDef) {
+ if (std::any_of(bmhDef.fChildren.begin(), bmhDef.fChildren.end(), [](Definition* def) {
+ return MarkType::kDeprecated == def->fMarkType; } )) {
+ return nullptr;
+ }
auto doubleColon = bmhDef.fName.rfind("::");
if (string::npos == doubleColon) {
const auto& iGlobalMethod = fIFunctionMap.find(bmhDef.fName);
@@ -1862,7 +1866,9 @@
}
string className = bmhDef.fName.substr(0, doubleColon);
const auto& iClass = fIClassMap.find(className);
- SkASSERT(fIClassMap.end() != iClass);
+ if (fIClassMap.end() == iClass) {
+ return nullptr;
+ }
string methodName = bmhDef.fName.substr(doubleColon + 2);
auto& iTokens = iClass->second.fTokens;
const auto& iMethod = std::find_if(iTokens.begin(), iTokens.end(),
diff --git a/tools/bookmaker/includeWriter.cpp b/tools/bookmaker/includeWriter.cpp
index 17336bf..77851f6 100644
--- a/tools/bookmaker/includeWriter.cpp
+++ b/tools/bookmaker/includeWriter.cpp
@@ -891,21 +891,35 @@
this->indentIn(IndentKind::kMethodOut);
fIndentNext = false;
}
+ if (string::npos != method->fName.find("validate")) {
+ SkDebugf("");
+ }
if (method->fChildren.end() != std::find_if(method->fChildren.begin(), method->fChildren.end(),
[](const Definition* def) { return MarkType::kPopulate == def->fMarkType; } )) {
- int commentIndex = child.fParentIndex;
- auto iter = child.fParent->fTokens.begin();
- std::advance(iter, commentIndex);
- SkDEBUGCODE(bool sawMethod = MarkType::kMethod == iter->fMarkType);
- while (--commentIndex >= 0) {
- std::advance(iter, -1);
- if (Bracket::kSlashStar == iter->fBracket) {
- SkASSERT(sawMethod);
+ std::list<Definition>::iterator iter;
+ const Definition* childPtr = &child;
+ SkDEBUGCODE(bool sawMethod = false);
+ do {
+ int commentIndex = childPtr->fParentIndex;
+ iter = childPtr->fParent->fTokens.begin();
+ std::advance(iter, commentIndex);
+ SkDEBUGCODE(sawMethod |= MarkType::kMethod == iter->fMarkType);
+ while (--commentIndex >= 0) {
+ std::advance(iter, -1);
+ if (Bracket::kSlashStar == iter->fBracket) {
+ SkASSERT(sawMethod);
+ break;
+ }
+ SkASSERT(!sawMethod);
+ SkDEBUGCODE(sawMethod |= MarkType::kMethod == iter->fMarkType);
+ }
+ if (MarkType::kMethod != iter->fMarkType) {
break;
}
- SkASSERT(!sawMethod);
- SkDEBUGCODE(sawMethod = MarkType::kMethod == iter->fMarkType);
- }
+ childPtr = childPtr->fParent;
+ SkDEBUGCODE(sawMethod = true);
+ } while (true);
+ SkASSERT(Bracket::kSlashSlash == iter->fBracket || Bracket::kSlashStar == iter->fBracket);
this->lf(2);
this->writeString("/");
this->writeBlock(iter->length(), iter->fContentStart);
diff --git a/tools/bookmaker/mdOut.cpp b/tools/bookmaker/mdOut.cpp
index 49f8b86..b214b11 100644
--- a/tools/bookmaker/mdOut.cpp
+++ b/tools/bookmaker/mdOut.cpp
@@ -169,10 +169,6 @@
#undef kConstTDBase
#undef kTH_Center
-static void add_ref(string leadingSpaces, string ref, string* result) {
- *result += leadingSpaces + ref;
-}
-
static string preformat(string orig) {
string result;
for (auto c : orig) {
@@ -187,15 +183,6 @@
return result;
}
-static bool all_lower(string ref) {
- for (auto ch : ref) {
- if (!islower(ch)) {
- return false;
- }
- }
- return true;
-}
-
// from https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
void replace_all(string& str, const string& from, const string& to) {
SkASSERT(!from.empty());
@@ -276,19 +263,6 @@
return nullptr;
}
-static bool formula_or_code(Resolvable resolvable) {
- return Resolvable::kFormula == resolvable
- || Resolvable::kCode == resolvable;
-}
-
-static void fixup_const_function_name(string* ref) {
- const char spaceConst[] = " const";
- size_t spacePos = ref->rfind(spaceConst);
- if (string::npos != spacePos && spacePos == ref->length() - sizeof(spaceConst) + 1) {
- *ref = ref->substr(0, spacePos) + "_const";
- }
-}
-
struct BraceState {
BraceState(RootDefinition* root, string name, const char* ch, KeyWord last, KeyWord keyWord,
int count)
@@ -308,8 +282,11 @@
int fBraceCount;
};
-bool MdOut::hasWordSpace(string wordSpace) const {
- for (NameMap* names = fNames; names; names = names->fParent) {
+bool MdOut::DefinedState::hasWordSpace(string wordSpace) const {
+ if (!fNames->fRefMap.size()) {
+ return false;
+ }
+ for (const NameMap* names = fNames; names; names = names->fParent) {
if (names->fRefMap.end() != names->fRefMap.find(wordSpace)) {
return true;
}
@@ -317,558 +294,322 @@
return false;
}
-bool MdOut::phraseContinues(string phrase, string* priorWord, string* priorLink) const {
- for (NameMap* names = fNames; names; names = names->fParent) {
+bool MdOut::DefinedState::phraseContinues(string phrase, string* priorWord,
+ string* priorLink) const {
+ for (const NameMap* names = fNames; names; names = names->fParent) {
if (names->fRefMap.end() != names->fRefMap.find(phrase + ' ')) {
*priorWord = phrase;
return true;
}
if (names->fRefMap.end() != names->fRefMap.find(phrase)) {
*priorWord = phrase;
- *priorLink = names->fLinkMap.end() == names->fLinkMap.find(phrase) ? "" :
- names->fLinkMap[phrase];
+ auto linkIter = names->fLinkMap.find(phrase);
+ *priorLink = names->fLinkMap.end() == linkIter ? "" : linkIter->second;
return true;
}
}
return false;
}
-// adds spaces to see if found word is part of registered phrase
-// adds parens to see if found word is all-lowercase function (parens must be in source as well)
-string MdOut::addIncludeReferences(const char* refStart, const char* refEnd) {
- TextParser matrixParser(fMethod->fFileName, refStart, refEnd, fMethod->fLineCount);
- const char* bracket = matrixParser.anyOf("|=\n");
- bool inMatrix = bracket && ('|' == bracket[0] || '=' == bracket[0]);
- auto& globals = fBmhParser.fGlobalNames;
- string result;
- const char* start = refStart;
- string priorWord;
- string priorLink;
- string priorSeparator;
- do {
- const char* separatorStart = start;
- bool whiteSpace = start < refEnd && ' ' >= start[0];
- while (start < refEnd && !isalpha(start[0])) {
- whiteSpace &= ' ' >= start[0];
- ++start;
- }
- bool priorSpace = false;
- string separator(separatorStart, start - separatorStart);
- if ("" != priorWord && whiteSpace) {
- string wordSpace = priorWord + ' ';
- if (this->hasWordSpace(wordSpace)) {
- priorWord = wordSpace;
- priorSpace = true;
- }
- }
- if ("()" == separator.substr(0, 2)) {
- string funcRef = priorWord + "()";
- if (this->findLink(funcRef, &priorLink)) {
- priorWord = funcRef;
- separator = separator.substr(2);
- }
- }
- result += priorSeparator;
- priorSeparator = separator;
- const char* end = start;
- do {
- while (end < refEnd && (isalnum(end[0]) || '-' == end[0] || '_' == end[0])) {
- ++end;
- }
- if (end + 1 >= refEnd || '/' != end[0] || start == end || !isalpha(end[-1])
- || !isalpha(end[1])) {
- break; // stop unless pattern is xxx/xxx as in I/O
- }
- ++end; // skip slash
- } while (true);
- while (start != end && '-' == end[-1]) {
- --end;
- }
- if (start != end && end + 2 < refEnd && "()" == string(end, 2)) {
- string check = string(start, end - start);
- if (std::all_of(check.begin(), check.end(), [](char c) { return islower(c); })) {
- end += 2;
- }
- }
- if (start == end) {
- break;
- }
- string word(start, end - start);
- if (priorSpace) {
- string phrase = priorWord + word;
- if (this->phraseContinues(phrase, &priorWord, &priorLink)) {
- start = end;
- continue;
- }
- priorWord = priorWord.substr(0, priorWord.length() - 1);
- }
- string link;
- bool found;
- // TODO: operators have complicated parsing possibilities; handle the easiest for now
- if ("operator" == priorWord && '(' == separator.back()) {
- TextParser parser(fMethod->fFileName, separatorStart, refEnd, fMethod->fLineCount);
- parser.skipToEndBracket('(');
- const char* parenStart = parser.fChar;
- parser.skipToBalancedEndBracket('(', ')');
- word = priorWord + separator + string(parenStart + 1, parser.fChar - parenStart - 1);
- end = parser.fChar;
- priorWord = "";
- priorLink = "";
- priorSeparator = "";
- }
- {
- auto paramIter = fNames->fRefMap.find(word);
- if ((found = fNames->fRefMap.end() != paramIter) && paramIter->second) {
- SkAssertResult(fNames->fLinkMap.end() != fNames->fLinkMap.find(word));
- link = fNames->fLinkMap[word];
- }
- }
- if (!found && ("." == separator || "->" == separator || "()." == separator
- || "()->" == separator)) {
- if (('f' == word[0] && isupper(word[1])) || "()" == word.substr(word.length() - 2)
- || (end + 2 <= refEnd && "()" == string(end, 2))) {
- if (fNames->fRefMap.end() != fNames->fRefMap.find(priorWord)) {
- // find prior word's type in fMethod
- TextParser parser(fMethod);
- SkAssertResult(parser.containsWord(priorWord.c_str(), parser.fEnd,
- &parser.fChar));
- // look up class or struct; trival lookup only class/struct [& * const]
- while (parser.back(" ") || parser.back("&") || parser.back("*")
- || parser.back("const"))
- ;
- const char* structEnd = parser.fChar;
- parser.backupWord();
- if (structEnd != parser.fChar) {
- string structName(parser.fChar, structEnd - parser.fChar);
- if ("SkVector" == structName) {
- // TODO: populate global refmap with typedefs as well as structs
- structName = "SkPoint";
- }
- structName += "::" + word;
- // look for word as member of class or struct
- auto defIter = globals.fRefMap.find(structName);
- if (globals.fRefMap.end() == defIter) {
- structName += "()";
- defIter = globals.fRefMap.find(structName);
- }
- if (globals.fRefMap.end() != defIter) {
- found = true;
- SkASSERT(globals.fLinkMap.end() != globals.fLinkMap.find(structName));
- link = globals.fLinkMap[structName];
- } else {
- SkDebugf("probably missing struct or class member in bmh: ");
- SkDebugf("%s\n", structName.c_str());
- }
- }
- }
- if (!found) {
- auto& parentRefMap = fNames->fParent->fRefMap;
- auto priorIter = parentRefMap.find(priorWord);
- if (parentRefMap.end() == priorIter) {
- priorIter = parentRefMap.find(priorWord + "()");
- }
- if (parentRefMap.end() != priorIter) {
- Definition* priorDef = priorIter->second;
- TextParser parser(priorDef->fFileName, priorDef->fStart,
- priorDef->fContentStart, priorDef->fLineCount);
- parser.skipExact("#Method ");
- parser.skipSpace();
- parser.skipExact("const "); // optional
- parser.skipSpace();
- const char* start = parser.fChar;
- parser.skipToNonAlphaNum();
- string structName(start, parser.fChar - start);
- structName += "::" + word;
- auto defIter = globals.fRefMap.find(structName);
- if (globals.fRefMap.end() != defIter) {
- found = true;
- SkASSERT(globals.fLinkMap.end() != globals.fLinkMap.find(structName));
- link = globals.fLinkMap[structName];
- }
- }
- }
- } else {
- SkDebugf("probably missing () after function:");
- const char* debugStart = end - 20 < refStart ? refStart : end - 20;
- const char* debugEnd = end + 10 > refEnd ? refEnd : end + 10;
- SkDebugf("%.*s\n", debugEnd - debugStart, debugStart);
- SkDebugf("");
- }
- }
- if (!found && "::" == separator) {
- string fullRef = priorWord + "::" + word;
- found = this->findLink(fullRef, &link);
- }
- if (!found) {
- found = this->findLink(word, &link);
- }
- if (!found) {
- found = globals.fRefMap.end() != globals.fRefMap.find(word + ' ');
- }
- if (!found) {
- found = globals.fRefMap.end() != globals.fRefMap.find(word + "()");
- }
- if (!found) {
- if (!inMatrix) {
- SkDebugf("word %s not found\n", word.c_str());
- fBmhParser.fGlobalNames.fRefMap[word] = nullptr;
- }
- }
- result += "" == priorLink ? priorWord : this->anchorRef(priorLink, priorWord);
- priorWord = word;
- priorLink = link;
- start = end;
- } while (true);
- result += "" == priorLink ? priorWord : this->anchorRef(priorLink, priorWord);
- result += priorSeparator;
- return result;
-}
-
-// FIXME: preserve inter-line spaces and don't add new ones
-string MdOut::addReferences(const char* refStart, const char* refEnd,
- Resolvable resolvable) {
- if (Resolvable::kInclude == resolvable) { // test include resolving
- return this->addIncludeReferences(refStart, refEnd);
+void MdOut::DefinedState::setLink() {
+ fPriorDef = nullptr;
+ // TODO: operators have complicated parsing possibilities; handle the easiest for now
+ if (fMethod && "operator" == fPriorWord && '(' == fSeparator.back()) {
+ TextParser parser(fMethod->fFileName, fSeparatorStart, fRefEnd, fMethod->fLineCount);
+ parser.skipToEndBracket('(');
+ const char* parenStart = parser.fChar;
+ parser.skipToBalancedEndBracket('(', ')');
+ parser.skipExact("_const");
+ // consume whether we find it or not
+ fWord = fPriorWord + fSeparator + string(parenStart + 1, parser.fChar - parenStart - 1);
+ fEnd = parser.fChar;
+ this->backup();
}
- string result;
- MethodParser t(fRoot ? fRoot->fName : string(), fFileName, refStart, refEnd, fLineCount);
- bool lineStart = true;
-// bool structClassSet = false;
- string ref;
- string leadingSpaces;
- int distFromParam = 99;
- const char* lastLine = nullptr;
- vector<BraceState> braceStack;
- KeyWord lastKeyWord = KeyWord::kNone;
- KeyWord keyWord = KeyWord::kNone;
- if (Resolvable::kCode == resolvable) {
- braceStack.push_back({fRoot, fRoot->fName, t.fChar, lastKeyWord, keyWord, 0});
+ // TODO: constructors also have complicated parsing possibilities; handle the easiest
+ else if (fMethod && fRoot && fRoot->isStructOrClass() && fRoot->fName == fPriorWord
+ && '(' == fSeparator.back()) {
+ TextParser parser(fMethod->fFileName, fSeparatorStart, fRefEnd, fMethod->fLineCount);
+ parser.skipToEndBracket('(');
+ const char* parenStart = parser.fChar;
+ parser.skipToBalancedEndBracket('(', ')');
+ string testWord = fPriorWord + fSeparator
+ + string(parenStart + 1, parser.fChar - parenStart - 1);
+ string testLink;
+ if (this->findLink(testWord, &testLink, false)) {
+ // consume only if we find it
+ fWord = testWord;
+ fLink = testLink;
+ fEnd = parser.fChar;
+ this->backup();
+ return;
+ }
}
- do {
- ++distFromParam;
- const char* base = t.fChar;
- t.skipWhiteSpace();
- const char* wordStart = t.fChar;
- if (formula_or_code(resolvable) && !t.eof() && '"' == t.peek()) {
- t.next();
- t.skipToEndBracket('"');
- t.next();
- continue;
+ // look to see if text following ref is method qualifier
+ else if ((Resolvable::kYes == fResolvable || Resolvable::kClone == fResolvable)
+ && "(" == fSeparator && "" != fPriorLink) {
+ TextParser parser(fLastDef->fFileName, fSeparatorStart, fRefEnd, fLastDef->fLineCount);
+ parser.skipToBalancedEndBracket('(', ')');
+ string fullMethod = fPriorWord + string(parser.fStart, parser.fChar - parser.fStart);
+ string trimmed = trim_inline_spaces(fullMethod);
+ string testLink;
+ if (findLink(trimmed, &testLink, false)) {
+ fMethodName = fullMethod;
+ fWord = trimmed;
+ fLink = testLink;
+ fEnd = parser.fChar;
+ this->backup();
+ return;
}
- if (Resolvable::kCode == resolvable) {
- int priorBrace = braceStack.back().fBraceCount;
- int braceCount = priorBrace + t.skipToMethodStart();
- if (braceCount > priorBrace) {
- string name;
- if (KeyWord::kClass == keyWord || KeyWord::kStruct == keyWord) {
- name = ref;
- } else if (KeyWord::kClass == lastKeyWord && KeyWord::kPublic == keyWord) {
- SkASSERT(lastLine);
- TextParser parser(t.fFileName, lastLine, t.fChar, t.fLineCount);
- parser.skipSpace();
- SkAssertResult(parser.skipExact("class "));
- parser.skipSpace();
- const char* nameStart = parser.fChar;
- parser.skipToSpace();
- name = string(nameStart, parser.fChar - nameStart);
- }
- if ("" != name) {
- const Definition* classDef = this->isDefined(t, name, resolvable);
- if (!classDef) {
- string className = fRoot->csParent()->fName;
- string withRoot = className + "::" + name;
- classDef = this->isDefined(t, withRoot, resolvable);
- SkASSERT(classDef);
+ }
+ if ("." == fSeparator || "->" == fSeparator || "()." == fSeparator || "()->" == fSeparator) {
+ bool foundField = fWord.length() >= 2 && (('f' == fWord[0] && isupper(fWord[1]))
+ || "()" == fWord.substr(fWord.length() - 2)
+ || (fEnd + 2 <= fRefEnd && "()" == string(fEnd, 2)));
+ if (foundField) {
+ if (fMethod && fNames->fRefMap.end() != fNames->fRefMap.find(fPriorWord)) {
+ // find prior fWord's type in fMethod
+ TextParser parser(fMethod);
+ SkAssertResult(parser.containsWord(fPriorWord.c_str(), parser.fEnd,
+ &parser.fChar));
+ // look up class or struct; trival lookup only class/struct [& * const]
+ while (parser.back(" ") || parser.back("&") || parser.back("*")
+ || parser.back("const"))
+ ;
+ const char* structEnd = parser.fChar;
+ parser.backupWord();
+ if (structEnd != parser.fChar) {
+ string structName(parser.fChar, structEnd - parser.fChar);
+ if ("SkVector" == structName) {
+ // TODO: populate global refmap with typedefs as well as structs
+ structName = "SkPoint";
+ } else if ("SkIVector" == structName) {
+ structName = "SkIPoint";
}
- if (classDef->isRoot()) {
- fRoot = const_cast<Definition*>(classDef)->asRoot();
- t.setLocalName(name);
+ structName += "::" + fWord;
+ // look for fWord as member of class or struct
+ auto defIter = fGlobals->fRefMap.find(structName);
+ if (fGlobals->fRefMap.end() == defIter) {
+ structName += "()";
+ defIter = fGlobals->fRefMap.find(structName);
}
- }
- braceStack.push_back({fRoot, name, t.fChar, lastKeyWord, keyWord, braceCount});
- } else if (braceCount < priorBrace) {
- lastKeyWord = braceStack.back().fLastKey;
- keyWord = braceStack.back().fKeyWord;
- braceStack.pop_back();
- if (KeyWord::kClass == keyWord || KeyWord::kStruct == keyWord) {
- fRoot = braceStack.back().fRoot;
- t.setLocalName(braceStack.back().fName);
- }
- }
- } else {
- (void) t.skipToMethodStart();
- }
- const char* start = t.fChar;
- if (fParamEnd <= start) {
- fParamEnd = nullptr;
- }
- if (wordStart < start) {
- if (lineStart) {
- lineStart = false;
- } else {
- wordStart = base;
- }
- string nonWord = string(wordStart, start - wordStart);
- if (Resolvable::kFormula == resolvable) {
- string unbreakable;
- bool comma = false;
- for (char c : nonWord) {
- if (string::npos != string("\\`*_{}[]()#+-.!").find(c)) {
- unbreakable += '\\';
- }
- if (' ' == c && !comma) {
- unbreakable += " ";
+ if (fGlobals->fRefMap.end() != defIter) {
+ // example: dstInfo.width()
+ auto structIter = fGlobals->fLinkMap.find(structName);
+ SkASSERT(fGlobals->fLinkMap.end() != structIter);
+ fLink = structIter->second;
+ fPriorDef = defIter->second;
+ return;
} else {
- unbreakable += c;
+ SkDebugf("probably missing struct or class member in bmh: ");
+ SkDebugf("%s\n", structName.c_str());
}
- comma = ',' == c;
- }
- nonWord = unbreakable;
- }
- result += nonWord;
- if ('\n' != result.back()) {
- while (start > wordStart && '\n' == start[-1]) {
- result += '\n';
- --start;
}
}
- }
- if (lineStart) {
- lineStart = false;
+ auto& parentRefMap = fNames->fParent->fRefMap;
+ auto priorIter = parentRefMap.find(fPriorWord);
+ if (parentRefMap.end() == priorIter) {
+ priorIter = parentRefMap.find(fPriorWord + "()");
+ }
+ if (parentRefMap.end() != priorIter) {
+ Definition* priorDef = priorIter->second;
+ if (priorDef) {
+ TextParser parser(priorDef->fFileName, priorDef->fStart,
+ priorDef->fContentStart, priorDef->fLineCount);
+ parser.skipExact("#Method ");
+ parser.skipSpace();
+ parser.skipExact("const "); // optional
+ parser.skipSpace();
+ const char* start = parser.fChar;
+ parser.skipToNonAlphaNum();
+ string structName(start, parser.fChar - start);
+ structName += "::" + fWord;
+ auto defIter = fGlobals->fRefMap.find(structName);
+ if (fGlobals->fRefMap.end() != defIter) {
+ // example: imageInfo().width()
+ auto globalIter = fGlobals->fLinkMap.find(structName);
+ SkASSERT(fGlobals->fLinkMap.end() != globalIter);
+ fLink = globalIter->second;
+ fPriorDef = defIter->second;
+ return;
+ }
+ }
+ }
} else {
- leadingSpaces = string(base, wordStart - base);
+ string fullRef = fPriorWord + fSeparator + fWord;
+ if (this->findLink(fullRef, &fLink, false)) {
+ return;
+ }
+ if (Resolvable::kCode != fResolvable) {
+ SkDebugf("probably missing () after function:");
+ const char* debugStart = fEnd - 20 < fRefStart ? fRefStart : fEnd - 20;
+ const char* debugEnd = fEnd + 10 > fRefEnd ? fRefEnd : fEnd + 10;
+ SkDebugf("%.*s\n", debugEnd - debugStart, debugStart);
+ SkDebugf(""); // convenient place to set a breakpoint
+ }
}
- t.skipToMethodEnd(resolvable);
- if (base == t.fChar) {
- if (!t.eof() && '~' == base[0] && !isalnum(base[1])) {
- t.next();
- } else {
+ }
+ // example: SkCanvas::restoreToCount
+ if ("::" == fSeparator) {
+ string fullRef = fPriorWord + "::" + fWord;
+ if (this->findLink(fullRef, &fLink, fAddParens)) {
+ return;
+ }
+ }
+ // look in parent fNames and above for match
+ if (fNames) {
+ if (this->findLink(fWord, &fLink, Resolvable::kClone == fResolvable && fAddParens)) {
+ return;
+ }
+ }
+ // example : sqrt as in "sqrt(x * x + y * y)"
+ // example : erase in seeAlso
+ if (Resolvable::kClone == fResolvable || (fEnd + 1 < fRefEnd && '(' == fEnd[0])) {
+ if (fAddParens && this->findLink(fWord + "()", &fLink, false)) {
+ return;
+ }
+ }
+ // example: Color_Type
+ if (this->findLink(fWord, &fLink, fBmhParser->fAliasMap)) {
+ return;
+ }
+ if (Resolvable::kInclude != fResolvable && string::npos != fWord.find('_')) {
+ // example: Blend_Mode
+ if (this->findLink(fWord, &fLink, fBmhParser->fTopicMap)) {
+ return;
+ }
+ if (fSubtopic) {
+ // example: Fake_Bold
+ if (fSubtopic->fName == fWord) {
+ fLink = '#' + fSubtopic->fFiddle;
+ fPriorDef = fSubtopic;
+ return;
+ }
+ const Definition* rootTopic = fSubtopic->subtopicParent();
+ if (rootTopic) {
+ if (rootTopic->fFiddle == fWord) {
+ fLink = '#' + rootTopic->fFiddle;
+ fPriorDef = rootTopic;
+ return;
+ }
+ string globName = rootTopic->fFiddle + '_' + fWord;
+ if (this->findLink(globName, &fLink, fBmhParser->fTopicMap)) {
+ return;
+ }
+ }
+ }
+ if (fRoot) {
+ string test = fRoot->fName + "::" + fWord;
+ auto rootIter = fRoot->fLeaves.find(test);
+ // example: restoreToCount in subtopic State_Stack
+ if (fRoot->fLeaves.end() != rootIter) {
+ fLink = '#' + rootIter->second.fFiddle;
+ fPriorDef = &rootIter->second;
+ return;
+ }
+ }
+ }
+ if (isupper(fWord[0]) && string::npos != fWord.find('_')) {
+ const Definition* topical = fSubtopic;
+ do {
+ string subtopic = topical->fName + '_' + fWord;
+ // example: Stroke_Width
+ if (this->findLink(subtopic, &fLink, fBmhParser->fTopicMap)) {
+ return;
+ }
+ } while ((topical = topical->topicParent()));
+ }
+ // treat hex constants as known words
+ if (fSeparator.size() > 0 && '0' == fSeparator.back() && 'x' == fWord[0]) {
+ bool allHex = true;
+ for (size_t index = 1; index < fWord.size(); ++index) {
+ char c = fWord[index];
+ if (('0' > c || '9' < c) && ('A' > c || 'F' < c)) {
+ allHex = false;
break;
}
}
- if (start >= t.fChar) {
- continue;
+ if (allHex) {
+ return;
}
- if (!t.eof() && '"' == t.peek() && start > wordStart && '"' == start[-1]) {
- continue;
+ }
+ // treat floating constants as known words
+ if ("e" == fWord) {
+ if (std::all_of(fSeparator.begin(), fSeparator.end(), [](char c) {
+ return isdigit(c) || '.' == c || '-' == c || ' ' >= c;
+ })) {
+ return;
}
- ref = string(start, t.fChar - start);
- if (fParamEnd
- && islower(start[0]) && ('k' != start[0] || !isupper(start[1]))) {
- if (' ' == start[-1] && ' ' != result.back()) {
- result += ' ';
+ }
+ // stop short of parsing example; just look to see if it contains fWord in description
+ if (fLastDef && MarkType::kDescription == fLastDef->fMarkType) {
+ Definition* example = fLastDef->fParent;
+ if (MarkType::kExample == example->fMarkType) {
+ // example text is blocked by last child before std out, if it exists
+ const char* exStart = example->fChildren.back()->fContentEnd;
+ const char* exEnd = example->fContentEnd;
+ if (MarkType::kStdOut == example->fChildren.back()->fMarkType) {
+ exStart = example->fChildren[example->fChildren.size() - 2]->fContentEnd;
+ exEnd = example->fChildren.back()->fContentStart;
}
- result += ref;
- continue;
- }
- if (Resolvable::kCode == resolvable) {
- fixup_const_function_name(&ref);
- }
- if (Definition* def = this->isDefined(t, ref, resolvable)) {
- if (MarkType::kExternal == def->fMarkType) {
- (void) this->anchorRef("undocumented#" + ref, ""); // for anchor validate
- add_ref(leadingSpaces, ref, &result);
- continue;
- }
- SkASSERT(def->fFiddle.length());
- if (Resolvable::kSimple != resolvable
- && Resolvable::kInclude != resolvable
- && !t.eof() && '(' == t.peek() && t.strnchr(')', t.fEnd)) {
- TextParserSave tSave(&t);
- if (!t.skipToBalancedEndBracket('(', ')')) {
- tSave.restore();
- t.reportError("missing close paren");
- fAddRefFailed = true;
- return result;
- }
-// t.next();
- SkASSERT(')' == t.fChar[-1]);
- fParamEnd = t.fChar - 1; // don't resolve lower case words til param end
- string fullRef = string(start, t.fChar - start);
- // if _2 etc alternates are defined, look for paren match
- // may ignore () if ref is all lower case and resolvable is not code
- // otherwise flag as error
- int suffix = '2';
- bool foundMatch = false;
- Definition* altDef = def;
- while (altDef && suffix <= '9') {
- if ((foundMatch = altDef->paramsMatch(fullRef, ref))) {
- def = altDef;
- ref = fullRef;
- break;
- }
- string altTest = ref + '_';
- altTest += suffix++;
- altDef = this->isDefined(t, altTest, Resolvable::kOut);
- }
- if (suffix > '9') {
- t.reportError("too many alts");
- fAddRefFailed = true;
- return result;
- }
- if (!foundMatch) {
- if (!(def = this->isDefined(t, fullRef, resolvable))) {
- if (formula_or_code(resolvable)) {
- // TODO: look for looser mapping -- if methods name match, look for
- // unique mapping based on number of parameters
- // for now, just look for function name match
- def = this->isDefined(t, ref, resolvable);
- }
- if (!def && !result.size()) {
- t.reportError("missing method");
- fAddRefFailed = true;
- return result;
- }
- }
- ref = fullRef;
- }
- ref = ref.substr(0, ref.find('('));
- tSave.restore();
- } else if (Resolvable::kClone != resolvable &&
- all_lower(ref) && (t.eof() || '(' != t.peek())) {
- add_ref(leadingSpaces, ref, &result);
- continue;
- }
- if (!def) {
- t.reportError("missing method");
- fAddRefFailed = true;
- return result;
- }
- result += linkRef(leadingSpaces, def, ref, resolvable);
- if (!t.eof() && '(' == t.peek()) {
- if (Resolvable::kInclude == resolvable
- && std::any_of(ref.begin(), ref.end(), [](char c){ return !islower(c); } )) {
- t.next(); // skip open paren
- SkAssertResult(')' == t.next()); // skip close paren
- continue;
- }
- result += t.next(); // skip open paren
- }
- continue;
- }
- if (!t.eof() && '(' == t.peek()) {
- if (!t.skipToEndBracket(')')) {
- t.reportError("missing close paren");
- fAddRefFailed = true;
- return result;
- }
- t.next();
- ref = string(start, t.fChar - start);
- if (Definition* def = this->isDefined(t, ref, Resolvable::kYes)) {
- SkASSERT(def->fFiddle.length());
- result += linkRef(leadingSpaces, def, ref, resolvable);
- continue;
+ // maybe need a general function that searches block text excluding children
+ TextParser exParse(example->fFileName, exStart, exEnd, example->fLineCount);
+ if (exParse.containsWord(fWord.c_str(), exParse.fEnd, nullptr)) {
+ return;
}
}
-// class, struct, and enum start with capitals
-// methods may start with upper (static) or lower (most)
+ }
+ // example: (x1, y1) after arcTo(SkScalar x1, ...
+ if (Resolvable::kYes == fResolvable && "" != fSeparator
+ && ('(' == fSeparator.back() || ',' == fSeparator[0])
+ && string::npos != fMethodName.find(fWord)) {
+ return;
+ }
+ // example: <sup> (skip html)
+ if (Resolvable::kYes == fResolvable && fEnd + 1 < fRefEnd && '>' == fEnd[0] && "" != fSeparator
+ && ('<' == fSeparator.back() || (fSeparator.size() >= 2
+ && "</" == fSeparator.substr(fSeparator.size() - 2)))) {
+ return;
+ }
+ // TODO: can probably resolve formulae, but need a way for formula to define new reference
+ // for example: Given: #Formula # Sa ## as source Alpha,
+ // for example: where #Formula # m = Da > 0 ? Dc / Da : 0 ##;
+ if (!fInProgress && Resolvable::kSimple != fResolvable
+ && Resolvable::kCode != fResolvable && Resolvable::kFormula != fResolvable) {
+ // example: Coons as in "Coons patch"
+ bool withSpace = fEnd + 1 < fRefEnd && ' ' == fEnd[0]
+ && fGlobals->fRefMap.end() != fGlobals->fRefMap.find(fWord + ' ');
+ if (!withSpace && (Resolvable::kInclude == fResolvable ? !fInMatrix :
+ '"' != fPriorSeparator.back() || '"' != fSeparator.back())) {
+ SkDebugf("fWord %s not found\n", fWord.c_str());
+ fBmhParser->fGlobalNames.fRefMap[fWord] = nullptr;
+ }
+ }
+}
- // see if this should have been a findable reference
- // look for Sk / sk / SK ..
- if (!ref.compare(0, 2, "Sk") && ref != "Skew" && ref != "Skews" && ref != "Skewing"
- && ref != "Skip" && ref != "Skips") {
- if (Resolvable::kOut != resolvable && !formula_or_code(resolvable)) {
- t.reportError("missed Sk prefixed");
- fAddRefFailed = true;
- return result;
- }
+string MdOut::addReferences(const char* refStart, const char* refEnd, Resolvable resolvable) {
+ DefinedState s(*this, refStart, refEnd, resolvable);
+ string result;
+ const char* start = refStart;
+ do {
+ s.fSeparatorStart = start;
+ start = s.skipWhiteSpace();
+ s.skipParens();
+ result += s.nextSeparator(start);
+ if (s.findEnd(start)) {
+ break;
}
- if (!ref.compare(0, 2, "SK")) {
- if (Resolvable::kOut != resolvable && !formula_or_code(resolvable)) {
- t.reportError("missed SK prefixed");
- fAddRefFailed = true;
- return result;
- }
- }
- if (!isupper(start[0])) {
- // TODO:
- // look for all lowercase w/o trailing parens as mistaken method matches
- // will also need to see if Example Description matches var in example
- Definition* def = nullptr;
- if (fMethod && (def = fMethod->hasParam(ref))) {
- result += linkRef(leadingSpaces, def, ref, resolvable);
- fLastParam = def;
- distFromParam = 0;
- continue;
- } else if (!fInDescription && ref[0] != '0'
- && string::npos != ref.find_first_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
- // FIXME: see isDefined(); check to see if fXX is a member of xx.fXX
- if (('f' != ref[0] && string::npos == ref.find("()"))
-// || '.' != t.backup(ref.c_str())
- && ('k' != ref[0] && string::npos == ref.find("_Private"))) {
- if ('.' == wordStart[0] && (distFromParam >= 1 && distFromParam <= 16)) {
- Definition* paramType = this->findParamType();
- if (paramType) {
- string fullName = paramType->fName + "::" + ref;
- if (paramType->hasMatch(fullName)) {
- result += linkRef(leadingSpaces, paramType, ref, resolvable);
- continue;
- }
- }
- }
- if (Resolvable::kSimple != resolvable
- && Resolvable::kInclude != resolvable
- && Resolvable::kOut != resolvable
- && !formula_or_code(resolvable)) {
- t.reportError("missed camelCase");
- fAddRefFailed = true;
- return result;
- }
- }
- }
- KeyWord newKeyWord = IncludeParser::FindKey(start, start + ref.length());
- lastLine = nullptr;
- if (KeyWord::kPrivate != newKeyWord && KeyWord::kProtected != newKeyWord
- && KeyWord::kPublic != newKeyWord) {
- lastKeyWord = keyWord;
- keyWord = newKeyWord;
- } else if (Resolvable::kCode == resolvable && ':' != t.peek()) {
- lastLine = t.fLine;
- lastKeyWord = keyWord;
- keyWord = newKeyWord;
- }
- add_ref(leadingSpaces, ref, &result);
+ s.fWord = string(start, s.fEnd - start);
+ s.setLower();
+ if (s.setPriorSpaceWord(&start)) {
continue;
}
- auto topicIter = fBmhParser.fTopicMap.find(ref);
- if (topicIter != fBmhParser.fTopicMap.end()) {
- result += linkRef(leadingSpaces, topicIter->second, ref, resolvable);
- continue;
- }
- bool startsSentence = t.sentenceEnd(start);
- if (!t.eof() && ' ' != t.peek()) {
- add_ref(leadingSpaces, ref, &result);
- continue;
- }
- if (t.fChar + 1 >= t.fEnd || (!isupper(t.fChar[1]) && startsSentence)) {
- add_ref(leadingSpaces, ref, &result);
- continue;
- }
- if (isupper(t.fChar[1]) && startsSentence) {
- TextParser next(t.fFileName, &t.fChar[1], t.fEnd, t.fLineCount);
- string nextWord(next.fChar, next.wordEnd() - next.fChar);
- if (this->isDefined(t, nextWord, Resolvable::kYes)) {
- add_ref(leadingSpaces, ref, &result);
- continue;
- }
- }
- Definition* def = this->checkParentsForMatch(fSubtopic, ref);
- if (!def) {
- def = this->checkParentsForMatch(fRoot, ref);
- }
- if (def) {
- result += this->linkRef(leadingSpaces, def, ref, resolvable);
- continue;
- }
- if (Resolvable::kOut != resolvable &&
- !formula_or_code(resolvable)) {
- t.reportError("undefined reference");
- fAddRefFailed = true;
- } else {
- add_ref(leadingSpaces, ref, &result);
- }
- } while (!t.eof());
+ s.setLink();
+ result += "" == s.fPriorLink ? s.fPriorWord : this->anchorRef(s.fPriorLink, s.fPriorWord);
+ start = s.nextWord();
+ } while (true);
+ result += "" == s.fPriorLink ? s.fPriorWord : this->anchorRef(s.fPriorLink, s.fPriorWord);
+ result += s.fPriorSeparator;
return result;
}
@@ -918,6 +659,9 @@
if (SkStrEndsWith(name, "illustrations.bmh")) { // don't look inside this for now
return true;
}
+ if (SkStrEndsWith(name, "undocumented.bmh")) { // don't look inside this for now
+ return true;
+ }
fFileName = string(name);
string filename(name);
if (filename.substr(filename.length() - 4) == ".bmh") {
@@ -1082,7 +826,8 @@
if (!islower(descriptionStart[0]) && !isdigit(descriptionStart[0])) {
paramBody.skipToNonName();
string ref = string(descriptionStart, paramBody.fChar - descriptionStart);
- if (!this->isDefined(paramBody, ref, Resolvable::kYes)) {
+ if (!std::all_of(ref.begin(), ref.end(), [](char c) { return isupper(c); })
+ && !this->isDefined(paramBody, Resolvable::kYes)) {
string errorStr = MarkType::kReturn == def->fMarkType ? "return" : "param";
errorStr += " description must start with lower case";
paramBody.reportError(errorStr.c_str());
@@ -1115,6 +860,9 @@
}
end = child->fStart;
if (Resolvable::kNo != resolvable) {
+ if (def->isStructOrClass() || MarkType::kEnumClass == def->fMarkType) {
+ fNames = &def->asRoot()->fNames;
+ }
this->resolveOut(start, end, resolvable);
}
this->markTypeOut(child, &prior);
@@ -1202,34 +950,60 @@
return csParent;
}
-bool MdOut::findLink(string word, string* linkPtr) {
- NameMap* names = fNames;
- while ((names = names->fParent)) {
+bool MdOut::DefinedState::findLink(string word, string* linkPtr, bool addParens) {
+ const NameMap* names = fNames;
+ do {
auto localIter = names->fRefMap.find(word);
if (names->fRefMap.end() != localIter) {
- if (localIter->second) {
- SkAssertResult(names->fLinkMap.end() != names->fLinkMap.find(word));
- *linkPtr = names->fLinkMap[word];
+ if ((fPriorDef = localIter->second)) {
+ auto linkIter = names->fLinkMap.find(word);
+ SkAssertResult(names->fLinkMap.end() != linkIter);
+ *linkPtr = linkIter->second;
}
return true;
}
if (!names->fParent && isupper(word[0])) {
- SkASSERT(names == &fBmhParser.fGlobalNames);
+ SkASSERT(names == &fBmhParser->fGlobalNames);
string lower = (char) tolower(word[0]) + word.substr(1);
auto globalIter = names->fRefMap.find(lower);
if (names->fRefMap.end() != globalIter) {
- if (globalIter->second) {
- SkAssertResult(names->fLinkMap.end() != names->fLinkMap.find(lower));
- *linkPtr = names->fLinkMap[lower];
+ if ((fPriorDef = globalIter->second)) {
+ auto lowerIter = names->fLinkMap.find(lower);
+ SkAssertResult(names->fLinkMap.end() != lowerIter);
+ *linkPtr = lowerIter->second;
}
return true;
}
}
+ if (addParens) {
+ string parenWord = word + "()";
+ auto paramIter = names->fRefMap.find(parenWord);
+ if (names->fRefMap.end() != paramIter) {
+ if ((fPriorDef = paramIter->second)) {
+ auto parenIter = names->fLinkMap.find(parenWord);
+ SkAssertResult(names->fLinkMap.end() != parenIter);
+ *linkPtr = parenIter->second;
+ }
+ return true;
+ }
+ }
+ } while ((names = names->fParent));
+ return false;
+}
+
+bool MdOut::DefinedState::findLink(string word, string* linkPtr,
+ unordered_map<string, Definition*>& map) {
+ auto mapIter = map.find(word);
+ if (map.end() != mapIter) {
+ if ((fPriorDef = mapIter->second)) {
+ *linkPtr = '#' + mapIter->second->fFiddle;
+ }
+ return true;
}
return false;
}
-Definition* MdOut::findParamType() {
+const Definition* MdOut::findParamType() {
SkASSERT(fMethod);
TextParser parser(fMethod->fFileName, fMethod->fStart, fMethod->fContentStart,
fMethod->fLineCount);
@@ -1244,8 +1018,7 @@
SkASSERT(!parser.eof());
string name = string(word, parser.fChar - word);
if (fLastParam->fName == name) {
- Definition* paramType = this->isDefined(parser, lastFull,
- Resolvable::kOut);
+ const Definition* paramType = this->isDefined(parser, Resolvable::kOut);
return paramType;
}
if (isupper(name[0])) {
@@ -1303,185 +1076,22 @@
FPRINTF("%s", s.c_str());
}
-Definition* MdOut::isDefinedByParent(RootDefinition* root, string ref) {
- if (ref == root->fName) {
- return root;
- }
- if (Definition* definition = root->find(ref, RootDefinition::AllowParens::kYes)) {
- return definition;
- }
- Definition* test = root;
- bool isSubtopic = MarkType::kSubtopic == root->fMarkType
- || MarkType::kTopic == root->fMarkType;
+const Definition* MdOut::isDefined(const TextParser& parser, Resolvable resolvable) {
+ DefinedState s(*this, parser.fStart, parser.fEnd, resolvable);
+ const char* start = parser.fStart;
do {
- if (!test->isRoot()) {
- continue;
- }
- bool testIsSubtopic = MarkType::kSubtopic == test->fMarkType
- || MarkType::kTopic == test->fMarkType;
- if (isSubtopic != testIsSubtopic) {
- continue;
- }
- RootDefinition* root = test->asRoot();
- for (auto& leaf : root->fBranches) {
- if (ref == leaf.first) {
- return leaf.second;
- }
- Definition* definition = leaf.second->find(ref,
- RootDefinition::AllowParens::kYes);
- if (definition) {
- return definition;
- }
- }
- string prefix = isSubtopic ? "_" : "::";
- string prefixed = root->fName + prefix + ref;
- if (Definition* definition = root->find(prefixed, RootDefinition::AllowParens::kYes)) {
- return definition;
- }
- if (isSubtopic && isupper(prefixed[0])) {
- auto topicIter = fBmhParser.fTopicMap.find(prefixed);
- if (topicIter != fBmhParser.fTopicMap.end()) {
- return topicIter->second;
- }
- }
- if (isSubtopic) {
- string fiddlePrefixed = root->fFiddle + "_" + ref;
- auto topicIter = fBmhParser.fTopicMap.find(fiddlePrefixed);
- if (topicIter != fBmhParser.fTopicMap.end()) {
- return topicIter->second;
- }
- }
- } while ((test = test->fParent));
- return nullptr;
-}
-
-Definition* MdOut::isDefined(const TextParser& parser, string ref,
- Resolvable resolvable) {
- auto rootIter = fBmhParser.fClassMap.find(ref);
- if (rootIter != fBmhParser.fClassMap.end()) {
- return &rootIter->second;
- }
- auto typedefIter = fBmhParser.fTypedefMap.find(ref);
- if (typedefIter != fBmhParser.fTypedefMap.end()) {
- return &typedefIter->second;
- }
- auto enumIter = fBmhParser.fEnumMap.find(ref);
- if (enumIter != fBmhParser.fEnumMap.end()) {
- return &enumIter->second;
- }
- auto constIter = fBmhParser.fConstMap.find(ref);
- if (constIter != fBmhParser.fConstMap.end()) {
- return &constIter->second;
- }
- auto methodIter = fBmhParser.fMethodMap.find(ref);
- if (methodIter != fBmhParser.fMethodMap.end()) {
- return &methodIter->second;
- }
- auto aliasIter = fBmhParser.fAliasMap.find(ref);
- if (aliasIter != fBmhParser.fAliasMap.end()) {
- return aliasIter->second;
- }
- auto defineIter = fBmhParser.fDefineMap.find(ref);
- if (defineIter != fBmhParser.fDefineMap.end()) {
- return &defineIter->second;
- }
- for (auto& external : fBmhParser.fExternals) {
- if (external.fName == ref) {
- return &external;
- }
- }
- if (Definition* definition = this->isDefinedByParent(fRoot, ref)) {
- return definition;
- }
- if (Definition* definition = this->isDefinedByParent(fSubtopic, ref)) {
- return definition;
- }
- size_t doubleColon = ref.find("::");
- if (string::npos != doubleColon) {
- string className = ref.substr(0, doubleColon);
- auto classIter = fBmhParser.fClassMap.find(className);
- if (classIter != fBmhParser.fClassMap.end()) {
- RootDefinition& classDef = classIter->second;
- Definition* result = classDef.find(ref, RootDefinition::AllowParens::kYes);
- if (result) {
- return result;
- }
- }
-
- }
- if (!ref.compare(0, 2, "SK") || !ref.compare(0, 3, "sk_")
- || (('k' == ref[0] || 'g' == ref[0] || 'f' == ref[0]) &&
- ref.length() > 1 && isupper(ref[1]))) {
- // try with a prefix
- if ('k' == ref[0]) {
- for (auto& iter : fBmhParser.fEnumMap) {
- auto def = iter.second.find(ref, RootDefinition::AllowParens::kYes);
- if (def) {
- return def;
- }
- }
- if (fEnumClass) {
- string fullName = fEnumClass->fName + "::" + ref;
- for (auto child : fEnumClass->fChildren) {
- if (fullName == child->fName) {
- return child;
- }
- }
- }
- if (string::npos != ref.find("_Private")) {
- return nullptr;
- }
- }
- if ('f' == ref[0]) {
- // FIXME : find def associated with prior, e.g.: r.fX where 'SkPoint r' was earlier
- // need to have pushed last resolve on stack to do this
- // for now, just try to make sure that it's there and error if not
- if ('.' != parser.backup(ref.c_str())) {
- parser.reportError("fX member undefined");
- fAddRefFailed = true;
- return nullptr;
- }
- } else {
- if (Resolvable::kOut != resolvable &&
- !formula_or_code(resolvable)) {
- parser.reportError("SK undefined");
- fAddRefFailed = true;
- }
+ s.fSeparatorStart = start;
+ start = s.skipWhiteSpace();
+ s.skipParens();
+ (void) s.nextSeparator(start);
+ if (s.findEnd(start)) {
return nullptr;
}
- }
- if (isupper(ref[0])) {
- auto topicIter = fBmhParser.fTopicMap.find(ref);
- if (topicIter != fBmhParser.fTopicMap.end()) {
- return topicIter->second;
- }
- size_t pos = ref.find('_');
- if (string::npos != pos) {
- // see if it is defined by another base class
- string className(ref, 0, pos);
- auto classIter = fBmhParser.fClassMap.find(className);
- if (classIter != fBmhParser.fClassMap.end()) {
- if (Definition* definition = classIter->second.find(ref,
- RootDefinition::AllowParens::kYes)) {
- return definition;
- }
- }
- auto enumIter = fBmhParser.fEnumMap.find(className);
- if (enumIter != fBmhParser.fEnumMap.end()) {
- if (Definition* definition = enumIter->second.find(ref,
- RootDefinition::AllowParens::kYes)) {
- return definition;
- }
- }
- if (Resolvable::kOut != resolvable &&
- !formula_or_code(resolvable)) {
- parser.reportError("_ undefined");
- fAddRefFailed = true;
- }
- return nullptr;
- }
- }
- return nullptr;
+ s.fWord = string(start, s.fEnd - start);
+ s.setLower();
+ } while (s.setPriorSpaceWord(&start));
+ s.setLink();
+ return s.fPriorDef;
}
string MdOut::linkName(const Definition* ref) const {
@@ -1499,137 +1109,6 @@
return result;
}
-// for now, hard-code to html links
-// def should not include SkXXX_
-string MdOut::linkRef(string leadingSpaces, Definition* def,
- string ref, Resolvable resolvable) {
- bool trimRef = Resolvable::kInclude == resolvable && "Sk" == ref.substr(0, 2);
- if (trimRef) {
-#ifdef SK_DEBUG
- for (auto c : ref) {
- SkASSERT(isalpha(c) || isdigit(c));
- }
-#endif
- ref = ref.substr(2);
- }
- string buildup;
- string refName;
- const string* str = &def->fFiddle;
- string classPart = *str;
- bool fromInclude = "" == classPart;
- if (fromInclude) {
- const Definition* parent = def->csParent();
- SkASSERT(parent);
- classPart = parent->fName;
- auto bmhMap = fBmhParser.fClassMap.find(classPart);
- auto defName = def->fParent->fName;
- SkASSERT(fBmhParser.fClassMap.end() != bmhMap);
- string fullName = classPart + "::" + defName;
- auto bmhDef = bmhMap->second.fLeaves.find(fullName);
- if (bmhMap->second.fLeaves.end() == bmhDef) {
- bmhDef = bmhMap->second.fLeaves.find(fullName + "()");
- }
- SkASSERT(bmhMap->second.fLeaves.end() != bmhDef);
- refName = bmhDef->second.fFiddle;
- refName += '_' + ref;
- }
- SkASSERT(classPart.length() > 0);
- bool globalEnumMember = false;
- if (MarkType::kAlias == def->fMarkType) {
- def = def->fParent;
- SkASSERT(def);
- SkASSERT(MarkType::kSubtopic == def->fMarkType
- || MarkType::kTopic == def->fMarkType
- || MarkType::kConst == def->fMarkType);
- }
- if (MarkType::kSubtopic == def->fMarkType) {
- const Definition* topic = def->topicParent();
- SkASSERT(topic);
- classPart = topic->fName;
- refName = def->fName;
- } else if (MarkType::kTopic == def->fMarkType) {
- refName = def->fName;
- } else {
- if ('k' == classPart[0] && string::npos != classPart.find("_Sk")) {
- globalEnumMember = true;
- } else {
- SkASSERT("Sk" == classPart.substr(0, 2) || "SK" == classPart.substr(0, 2)
- // FIXME: kitchen sink catch below, need to do better
- || string::npos != def->fFileName.find("undocumented"));
- size_t under = classPart.find('_');
- if (string::npos != under) {
- classPart = classPart.substr(0, under);
- }
- }
- if (!fromInclude) {
- refName = def->fFiddle;
- if (trimRef) {
- SkASSERT("Sk" == refName.substr(0, 2));
-#ifdef SK_DEBUG
- for (auto c : refName) {
- SkASSERT(isalpha(c) || isdigit(c));
- }
-#endif
- refName = refName.substr(2);
- }
- }
- }
- bool classMatch = fRoot->fFileName == def->fFileName || fromInclude;
- SkASSERT(fRoot);
- SkASSERT(fRoot->fFileName.length());
- if (!classMatch) {
- string filename = def->fFileName;
- if (filename.substr(filename.length() - 4) == ".bmh") {
- filename = filename.substr(0, filename.length() - 4);
- }
- size_t start = filename.length();
- while (start > 0 && (isalnum(filename[start - 1]) || '_' == filename[start - 1])) {
- --start;
- }
- buildup = filename.substr(start);
- }
- buildup += "#" + refName;
- if (MarkType::kParam == def->fMarkType) {
- const Definition* parent = def->fParent;
- SkASSERT(MarkType::kMethod == parent->fMarkType);
- buildup = '#' + parent->fFiddle + '_' + ref;
- }
- string refOut(ref);
- if (!globalEnumMember && Resolvable::kCode != resolvable) {
- std::replace(refOut.begin(), refOut.end(), '_', ' ');
- }
- if (ref.length() > 2 && islower(ref[0]) && "()" == ref.substr(ref.length() - 2)
- && Resolvable::kCode != resolvable) {
- refOut = refOut.substr(0, refOut.length() - 2);
- }
- string result = leadingSpaces + this->anchorRef(buildup, refOut);
- if (Resolvable::kClone == resolvable && MarkType::kMethod == def->fMarkType &&
- def->fCloned && !def->fClone) {
- bool found = false;
- string match = def->fName;
- if ("()" == match.substr(match.length() - 2)) {
- match = match.substr(0, match.length() - 2);
- }
- match += '_';
- auto classIter = fBmhParser.fClassMap.find(classPart);
- if (fBmhParser.fClassMap.end() != classIter) {
- for (char num = '2'; num <= '9'; ++num) {
- string clone = match + num;
- const auto& leafIter = classIter->second.fLeaves.find(clone);
- if (leafIter != classIter->second.fLeaves.end()) {
- result += "<sup>" + this->anchorRef(buildup + "_" + num,
- string("[") + num + "]") + "</sup>";
- found = true;
- }
- }
- }
- if (!found) {
- SkDebugf(""); // convenient place to set a breakpoint
- }
- }
- return result;
-}
-
static bool writeTableEnd(MarkType markType, Definition* def, const Definition** prior) {
return markType != def->fMarkType && *prior && markType == (*prior)->fMarkType;
}
@@ -1773,6 +1252,7 @@
fTableState = TableState::kNone;
}
fLastDef = def;
+ NameMap paramMap;
switch (def->fMarkType) {
case MarkType::kAlias:
break;
@@ -2041,6 +1521,18 @@
this->lf(2);
fTableState = TableState::kNone;
fMethod = def;
+ if ("SkTextBlobBuilder::allocRun_2" == def->fName) {
+ SkDebugf("");
+ }
+ Definition* iMethod = fIncludeParser.findMethod(*def);
+ if (iMethod) {
+ fMethod = iMethod;
+ paramMap.fParent = &fBmhParser.fGlobalNames;
+ paramMap.setParams(def, iMethod);
+ fNames = ¶mMap;
+ } else {
+ SkDebugf("");
+ }
} break;
case MarkType::kNoExample:
break;
@@ -2180,45 +1672,9 @@
SkASSERT(MarkType::kMethod == parent->fMarkType);
// retrieve parameters, return, description from include
Definition* iMethod = fIncludeParser.findMethod(*parent);
+ SkASSERT(iMethod); // deprecated or 'in progress' functions should not include populate
bool wroteParam = false;
- fMethod = iMethod;
- NameMap paramMap;
- Definition* pParent = def->csParent();
- string parentName;
- NameMap* parentMap;
- if (pParent) {
- parentName = pParent->fName + "::";
- parentMap = &pParent->asRoot()->fNames;
- } else {
- parentMap = &fBmhParser.fGlobalNames;
- }
- paramMap.fName = parentName + iMethod->fName;
- paramMap.fParent = parentMap;
- fNames = ¶mMap;
- TextParser methParams(iMethod);
- for (auto& param : iMethod->fTokens) {
- if (MarkType::kComment != param.fMarkType) {
- continue;
- }
- TextParser paramParser(¶m);
- if (!paramParser.skipExact("@param ")) { // write parameters, if any
- continue;
- }
- paramParser.skipSpace();
- const char* start = paramParser.fChar;
- paramParser.skipToSpace();
- string paramName(start, paramParser.fChar - start);
- #ifdef SK_DEBUG
- for (char c : paramName) {
- SkASSERT(isalnum(c) || '_' == c);
- }
- #endif
- if (!methParams.containsWord(paramName.c_str(), methParams.fEnd, nullptr)) {
- param.reportError<void>("mismatched param name");
- }
- paramMap.fRefMap[paramName] = ¶m;
- paramMap.fLinkMap[paramName] = '#' + def->fFiddle + '_' + paramName;
- }
+ SkASSERT(fMethod == iMethod);
for (auto& entry : iMethod->fTokens) {
if (MarkType::kComment != entry.fMarkType) {
continue;
@@ -2262,8 +1718,6 @@
Resolvable::kInclude); // write description
this->lf(1);
}
- fMethod = nullptr;
- fNames = fNames->fParent;
}
} break;
case MarkType::kPrivate:
@@ -2482,6 +1936,7 @@
} break;
case MarkType::kMethod:
fMethod = nullptr;
+ fNames = fNames->fParent;
break;
case MarkType::kConst:
case MarkType::kMember:
@@ -2916,7 +2371,6 @@
start = entry->fName.substr(0, start - 1).rfind("::");
}
string entryName = entry->fName.substr(string::npos == start ? 0 : start + 1);
-// fixup_const_function_name(&entry->fName);
items[entryName] = entry;
}
for (auto entry : items) {
@@ -2962,7 +2416,7 @@
return parser.reportError<bool>("missing #Line");
}
TextParser dummy(entry); // for reporting errors, which we won't do
- if (!this->isDefined(dummy, keyName, Resolvable::kOut)) {
+ if (!this->isDefined(dummy, Resolvable::kOut)) {
keyName = entry->fName;
size_t doubleColon = keyName.find("::");
SkASSERT(string::npos != doubleColon);
diff --git a/tools/bookmaker/mdOut.h b/tools/bookmaker/mdOut.h
index 30b48d8..8a10854 100644
--- a/tools/bookmaker/mdOut.h
+++ b/tools/bookmaker/mdOut.h
@@ -45,9 +45,159 @@
MarkType fMarkType;
};
+ struct DefinedState {
+ DefinedState(const MdOut& mdOut, const char* refStart, const char* refEnd,
+ Resolvable resolvable)
+ : fBmhParser(&mdOut.fBmhParser)
+ , fNames(mdOut.fNames)
+ , fGlobals(&mdOut.fBmhParser.fGlobalNames)
+ , fLastDef(mdOut.fLastDef)
+ , fMethod(mdOut.fMethod)
+ , fSubtopic(mdOut.fSubtopic)
+ , fRoot(mdOut.fRoot)
+ , fRefStart(refStart)
+ , fRefEnd(refEnd)
+ , fResolvable(resolvable)
+ , fInProgress(mdOut.fInProgress) {
+ TextParser matrixParser(fLastDef->fFileName, refStart, refEnd, fLastDef->fLineCount);
+ const char* bracket = matrixParser.anyOf("|=\n");
+ fInMatrix = bracket && ('|' == bracket[0] || '=' == bracket[0]);
+ }
+
+ void backup() {
+ fPriorWord = fBack2Word;
+ fPriorLink = "";
+ fPriorSeparator = "";
+ fSeparator = fBack2Separator;
+ }
+
+ bool findEnd(const char* start) {
+ do {
+ while (fEnd < fRefEnd && (isalnum(fEnd[0]) || '-' == fEnd[0] || '_' == fEnd[0])) {
+ ++fEnd;
+ }
+ if (fEnd + 1 >= fRefEnd || '/' != fEnd[0] || start == fEnd || !isalpha(fEnd[-1])
+ || !isalpha(fEnd[1])) {
+ break; // stop unless pattern is xxx/xxx as in I/O
+ }
+ ++fEnd; // skip slash
+ } while (true);
+ while (start != fEnd && '-' == fEnd[-1]) {
+ --fEnd;
+ }
+ return start == fEnd;
+ }
+
+ bool findLink(string ref, string* linkPtr, bool addParens);
+ bool findLink(string ref, string* linkPtr, unordered_map<string, Definition*>& map);
+ bool hasWordSpace(string wordSpace) const;
+ void setLink();
+
+ string nextSeparator(const char* start) {
+ fBack2Separator = fPriorSeparator;
+ fPriorSeparator = fSeparator;
+ fEnd = start;
+ return fBack2Separator;
+ }
+
+ const char* nextWord() {
+ fBack2Word = fPriorWord;
+ fPriorWord = fWord;
+ fPriorLink = fLink;
+ return fEnd;
+ }
+
+ bool phraseContinues(string phrase, string* priorWord, string* priorLink) const;
+
+ void setLower() {
+ fAddParens = false;
+ bool allLower = std::all_of(fWord.begin(), fWord.end(), [](char c) {
+ return islower(c);
+ });
+ bool hasParens = fEnd + 2 <= fRefEnd && "()" == string(fEnd, 2);
+ if (hasParens) {
+ if (allLower) {
+ fWord += "()";
+ fEnd += 2;
+ }
+ } else if (allLower) {
+ fAddParens = true;
+ }
+ }
+
+ bool setPriorSpaceWord(const char** startPtr) {
+ if (!fPriorSpace) {
+ return false;
+ }
+ string phrase = fPriorWord + fWord;
+ if (this->phraseContinues(phrase, &fPriorWord, &fPriorLink)) {
+ *startPtr = fEnd;
+ return true;
+ }
+ fPriorWord = fPriorWord.substr(0, fPriorWord.length() - 1);
+ return false;
+ }
+
+ void skipParens() {
+ if ("()" == fSeparator.substr(0, 2)) {
+ string funcRef = fPriorWord + "()";
+ if (this->findLink(funcRef, &fPriorLink, false)) {
+ fPriorWord = funcRef;
+ fSeparator = fSeparator.substr(2);
+ }
+ }
+ }
+
+ const char* skipWhiteSpace() {
+ const char* start = fSeparatorStart;
+ bool whiteSpace = start < fRefEnd && ' ' >= start[0];
+ while (start < fRefEnd && !isalpha(start[0])) {
+ whiteSpace &= ' ' >= start[0];
+ ++start;
+ }
+ fPriorSpace = false;
+ fSeparator = string(fSeparatorStart, start - fSeparatorStart);
+ if ("" != fPriorWord && whiteSpace) {
+ string wordSpace = fPriorWord + ' ';
+ if (this->hasWordSpace(wordSpace)) {
+ fPriorWord = wordSpace;
+ fPriorSpace = true;
+ }
+ }
+ return start;
+ }
+
+ string fRef;
+ string fBack2Word;
+ string fBack2Separator;
+ string fPriorWord;
+ string fPriorLink;
+ string fPriorSeparator;
+ string fWord;
+ string fLink;
+ string fSeparator;
+ string fMethodName;
+ BmhParser* fBmhParser;
+ const NameMap* fNames;
+ const NameMap* fGlobals;
+ const Definition* fLastDef;
+ const Definition* fMethod;
+ const Definition* fSubtopic;
+ const Definition* fPriorDef;
+ const RootDefinition* fRoot;
+ const char* fSeparatorStart;
+ const char* fRefStart;
+ const char* fRefEnd;
+ const char* fEnd;
+ Resolvable fResolvable;
+ bool fAddParens;
+ bool fInMatrix;
+ bool fInProgress;
+ bool fPriorSpace;
+ };
+
void addCodeBlock(const Definition* def, string& str) const;
void addPopulators();
- string addIncludeReferences(const char* refStart, const char* refEnd);
string addReferences(const char* start, const char* end, Resolvable );
string anchorDef(string def, string name);
string anchorLocalRef(string ref, string name);
@@ -57,23 +207,19 @@
Definition* checkParentsForMatch(Definition* test, string ref) const;
void childrenOut(Definition* def, const char* contentStart);
Definition* csParent();
- bool findLink(string ref, string* link);
- Definition* findParamType();
+ const Definition* findParamType();
string getMemberTypeName(const Definition* def, string* memberType);
static bool HasDetails(const Definition* def);
- bool hasWordSpace(string ) const;
void htmlOut(string );
- Definition* isDefined(const TextParser& , string ref, Resolvable );
- Definition* isDefinedByParent(RootDefinition* root, string ref);
+ bool isDefined(DefinedState& s);
+ const Definition* isDefined(const TextParser& , Resolvable );
string linkName(const Definition* ) const;
- string linkRef(string leadingSpaces, Definition*, string ref, Resolvable );
void markTypeOut(Definition* , const Definition** prior);
void mdHeaderOut(int depth) { mdHeaderOutLF(depth, 2); }
void mdHeaderOutLF(int depth, int lf);
void parameterHeaderOut(TextParser& paramParser, const Definition** prior, Definition* def);
void parameterTrailerOut();
bool parseFromFile(const char* path) override { return true; }
- bool phraseContinues(string phrase, string* priorWord, string* priorLink) const;
void populateOne(Definition* def,
unordered_map<string, RootDefinition::SubtopicContents>& populator);
void populateTables(const Definition* def, RootDefinition* );
diff --git a/tools/bookmaker/textParser.cpp b/tools/bookmaker/textParser.cpp
index 6ea4a24..0994d7b 100644
--- a/tools/bookmaker/textParser.cpp
+++ b/tools/bookmaker/textParser.cpp
@@ -6,6 +6,7 @@
*/
#include "definition.h"
+#include "textParser.h"
#ifdef SK_BUILD_FOR_WIN
#include <Windows.h>
diff --git a/tools/bookmaker/textParser.h b/tools/bookmaker/textParser.h
index eee1f7c..ffe5e78 100644
--- a/tools/bookmaker/textParser.h
+++ b/tools/bookmaker/textParser.h
@@ -623,6 +623,24 @@
trim_end(s);
}
+static inline string trim_inline_spaces(string s) {
+ bool lastSpace = false;
+ string trimmed;
+ for (const char* ptr = &s.front(); ptr <= &s.back(); ++ptr) {
+ char c = *ptr;
+ if (' ' >= c) {
+ if (!lastSpace) {
+ trimmed += ' ';
+ }
+ lastSpace = true;
+ continue;
+ }
+ lastSpace = false;
+ trimmed += c;
+ }
+ return trimmed;
+}
+
class EscapeParser : public TextParser {
public:
EscapeParser(const char* start, const char* end) :