blob: 8a10854a0330c6b3c905db575456a9f0920e024a [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef mdOut_DEFINED
#define mdOut_DEFINED
#include "parserCommon.h"
class IncludeParser;
class MdOut : public ParserCommon {
public:
struct SubtopicDescriptions {
string fSingular;
string fPlural;
string fOneLiner;
string fDetails;
};
MdOut(BmhParser& bmh, IncludeParser& inc) : ParserCommon()
, fBmhParser(bmh)
, fIncludeParser(inc) {
this->reset();
this->addPopulators();
fBmhParser.setUpGlobalSubstitutes();
}
bool buildReferences(const char* docDir, const char* mdOutDirOrFile);
bool buildStatus(const char* docDir, const char* mdOutDir);
void checkAnchors();
private:
enum class TableState {
kNone,
kRow,
kColumn,
};
struct AnchorDef {
string fDef;
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 addReferences(const char* start, const char* end, Resolvable );
string anchorDef(string def, string name);
string anchorLocalRef(string ref, string name);
string anchorRef(string def, string name);
bool buildRefFromFile(const char* fileName, const char* outDir);
bool checkParamReturnBody(const Definition* def);
Definition* checkParentsForMatch(Definition* test, string ref) const;
void childrenOut(Definition* def, const char* contentStart);
Definition* csParent();
const Definition* findParamType();
string getMemberTypeName(const Definition* def, string* memberType);
static bool HasDetails(const Definition* def);
void htmlOut(string );
bool isDefined(DefinedState& s);
const Definition* isDefined(const TextParser& , Resolvable );
string linkName(const Definition* ) const;
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; }
void populateOne(Definition* def,
unordered_map<string, RootDefinition::SubtopicContents>& populator);
void populateTables(const Definition* def, RootDefinition* );
SubtopicDescriptions& populator(string key) {
auto entry = fPopulators.find(key);
// FIXME: this should have been detected earlier
SkASSERT(fPopulators.end() != entry);
return entry->second;
}
void reset() override {
INHERITED::resetCommon();
fEnumClass = nullptr;
fMethod = nullptr;
fRoot = nullptr;
fSubtopic = nullptr;
fLastParam = nullptr;
fTableState = TableState::kNone;
fAddRefFailed = false;
fHasFiddle = false;
fInDescription = false;
fInList = false;
fResolveAndIndent = false;
fLiteralAndIndent = false;
fLastDef = nullptr;
fParamEnd = nullptr;
fInProgress = false;
}
Resolvable resolvable(const Definition* definition) const {
MarkType markType = definition->fMarkType;
if (MarkType::kCode == markType) {
for (auto child : definition->fChildren) {
if (MarkType::kLiteral == child->fMarkType) {
return Resolvable::kLiteral;
}
}
}
if ((MarkType::kExample == markType
|| MarkType::kFunction == markType) && fHasFiddle) {
return Resolvable::kNo;
}
return BmhParser::kMarkProps[(int) markType].fResolve;
}
void resolveOut(const char* start, const char* end, Resolvable );
void returnHeaderOut(const Definition** prior, Definition* def);
void rowOut(string col1, const Definition* col2);
void rowOut(const char * name, string description, bool literalName);
void subtopicOut(string name);
void subtopicsOut(Definition* def);
void subtopicOut(string key, const vector<Definition*>& data, const Definition* csParent,
const Definition* topicParent, bool showClones);
bool subtopicRowOut(string keyName, const Definition* entry);
void summaryOut(const Definition* def, MarkType , string name);
string tableDataCodeDef(const Definition* def);
string tableDataCodeDef(string def, string name);
string tableDataCodeLocalRef(string name);
string tableDataCodeLocalRef(string ref, string name);
string tableDataCodeRef(const Definition* ref);
string tableDataCodeRef(string ref, string name);
void writeSubtopicTableHeader(string key);
vector<const Definition*> fClassStack;
unordered_map<string, vector<AnchorDef> > fAllAnchorDefs;
unordered_map<string, vector<string> > fAllAnchorRefs;
NameMap* fNames;
BmhParser& fBmhParser;
IncludeParser& fIncludeParser;
const Definition* fEnumClass;
const Definition* fLastDef;
Definition* fMethod;
RootDefinition* fRoot; // used in generating populated tables; always struct or class
RootDefinition* fSubtopic; // used in resolving symbols
const Definition* fLastParam;
TableState fTableState;
unordered_map<string, SubtopicDescriptions> fPopulators;
unordered_map<string, string> fPhraseParams;
const char* fParamEnd;
bool fAddRefFailed;
bool fHasFiddle;
bool fInDescription; // FIXME: for now, ignore unfound camelCase in description since it may
// be defined in example which at present cannot be linked to
bool fInList;
bool fLiteralAndIndent;
bool fResolveAndIndent;
bool fOddRow;
bool fHasDetails;
bool fInProgress;
typedef ParserCommon INHERITED;
};
#endif