diff options
author | 2018-05-16 07:07:07 -0400 | |
---|---|---|
committer | 2018-05-16 11:35:24 +0000 | |
commit | 682c58da482155213e8cd2834b57bc6541e510a0 (patch) | |
tree | 63d666ea9ec0c2e765557e61e9ec5fc78ad9747f /tools/bookmaker/bookmaker.cpp | |
parent | 4c2a34e4804e5affa8447b590578a359bad2caf8 (diff) |
Documentation refresh
- add links to types within methods
- add check to see that all references and definitions match
- add style to tables to make them easier to read
- use https everywhere
- remove trailing spaces
- move overview inside class
- split class and struct in summary tables
- add missing #Line
- clean up SkImageInfo constant documentation
- work on SkColor documentation
- allow common phrases to take different parameters
- add more flexibility to generated tables
- tighten token parent requirements
- generalize deprecated and example interfaces
- detect inner constructors
R=caryclark@google.com
Docs-Preview: https://skia.org/?cl=121799
Bug: skia:6898
Change-Id: Ia75a23740b80259460916890b310e2a9f024962a
Reviewed-on: https://skia-review.googlesource.com/121799
Commit-Queue: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@skia.org>
Diffstat (limited to 'tools/bookmaker/bookmaker.cpp')
-rw-r--r-- | tools/bookmaker/bookmaker.cpp | 270 |
1 files changed, 206 insertions, 64 deletions
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp index 49e347e6ea..aaf3781974 100644 --- a/tools/bookmaker/bookmaker.cpp +++ b/tools/bookmaker/bookmaker.cpp @@ -29,18 +29,14 @@ DEFINE_string2(spellcheck, s, "", "Spell-check [once, all, mispelling]. (Require DEFINE_bool2(tokens, t, false, "Write bmh from include. (Requires -b -i)"); DEFINE_bool2(crosscheck, x, false, "Check bmh against includes. (Requires -b -i)"); // v is reserved for verbose +DEFINE_bool2(validate, V, false, "Validate that all anchor references have definitions. (Requires -r)"); DEFINE_bool2(skip, z, false, "Skip degenerate missed in legacy preprocessor."); -/* recipe for generating timestamps for existing doxygen comments -find include/core -type f -name '*.h' -print -exec git blame {} \; > ~/all.blame.txt +/* todos: + +add new markup to associate enum SaveLayerFlagsSet with typedef SaveLayerFlags, if needed. -todos: -add new markup to associate typedef SaveLayerFlags with Enum so that, for - documentation purposes, this enum is named rather than anonymous -check column 1 of subtopic tables to see that they start lowercase and don't have a trailing period -space table better for Constants should Return be on same line as 'Return Value'? -remove anonymous header, e.g. Enum SkPaint::::anonymous_2 #Member lost all formatting #List needs '# content ##', formatting consts like enum members need fully qualfied refs to make a valid link @@ -53,6 +49,45 @@ deprecated methods should be sorted down in md out, and show include "Deprecated rewrap text to fit in some number of columns #Literal is inflexible, making the entire #Code block link-less (see $Literal in SkImageInfo) would rather keep links for boby above #Literal, and/or make it a block and not a one-liner +add check to require #Const to contain #Code block if defining const or constexpr (enum consts have + #Code blocks inside the #Enum def +add spelling rule to look for x-bit but allow x bits + +There are a number of formatting bugs with ad hoc patches where a substitution doesn't keep +the space before or after, or the linefeeds before or after. The rules are not very good either. +Linefeeds in the bmh file are intended to be respected, but #Formula tends to start on a new line +even if the contents is intended to be inlined. Probably need to require it to be, e.g.: + + array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##. + +where there is always a space between prior words and formula (i.e., between "be" and "(fXCount"; +and, an absense of a space after ## denotes no space between "+ 1)" and ".". These rules preserve +that # commands are always preceded by a whitespace character. Similarly, #PhraseDef/Ref +need to be inline or create new paragraphs. #phrase_ref# is sufficiently flexible that it can be +treated as a word without trailing whitespace, adapting the whitespace of its context. It also must +always have leading whitespace. + +It's awkward that phrase param is a child of the phrase def. Since phrase refs may also be children, +there is special case code to skip phrase def when looking for additional substitutions in the +phrase def. Could put it in the token list instead I guess, or make a definition subclass used +by phrase def with an additional slot... + + + +#Deprecated soon +## +should emit the text "To be deprecated soon." (right now you get just "soon") + +SkCanvas_ColorBehavior_kLegacy missing </table> in md out + +rearrange const out for md so that const / value / short description comes first in a table, +followed by more elaborate descriptions, examples, seealso. In md.cpp, look to see if #Subtopic +has #Const children. If so, generate a summary table first. +Or, only allow #Line and moderate text description in #Const. Put more verbose text, example, +seealso, in subsequent #SubTopic. Alpha_Type does this and it looks good. + +more spelling: x-value y-value + see head of selfCheck.cpp for additional todos */ @@ -67,6 +102,8 @@ see head of selfCheck.cpp for additional todos #define M(mt) (1LL << (int) MarkType::k##mt) #define M_D M(Description) #define M_CS M(Class) | M(Struct) +#define M_MD M(Method) | M(Define) +#define M_MDCM M_MD | M(Const) | M(Member) #define M_ST M(Subtopic) | M(Topic) #define M_CSST M_CS | M_ST #ifdef M_E @@ -84,35 +121,35 @@ see head of selfCheck.cpp for additional todos #define E_N Exemplary::kNo #define E_O Exemplary::kOptional +// ToDo: add column to denote which marks are one-liners BmhParser::MarkProps BmhParser::kMarkProps[] = { // names without formal definitions (e.g. Column) aren't included -// fill in other names once they're actually used { "", MarkType::kNone, R_Y, E_N, 0 } , { "A", MarkType::kAnchor, R_N, E_N, 0 } -, { "Alias", MarkType::kAlias, R_N, E_N, 0 } -, { "Bug", MarkType::kBug, R_N, E_N, 0 } -, { "Class", MarkType::kClass, R_Y, E_O, M_CSST | M(Root) } -, { "Code", MarkType::kCode, R_F, E_N, M_CSST | M_E | M(Method) | M(Define) | M(Typedef) } +, { "Alias", MarkType::kAlias, R_N, E_N, M_ST | M(Const) } +, { "Bug", MarkType::kBug, R_N, E_N, M_CSST | M_MDCM | M_E + | M(Example) | M(NoExample) } +, { "Class", MarkType::kClass, R_Y, E_O, M_CSST } +, { "Code", MarkType::kCode, R_F, E_N, M_CSST | M_E | M_MD | M(Typedef) } , { "", MarkType::kColumn, R_Y, E_N, M(Row) } , { "", MarkType::kComment, R_N, E_N, 0 } , { "Const", MarkType::kConst, R_Y, E_O, M_E | M_ST } , { "Define", MarkType::kDefine, R_O, E_Y, M_ST } , { "DefinedBy", MarkType::kDefinedBy, R_N, E_N, M(Method) } -, { "Deprecated", MarkType::kDeprecated, R_Y, E_N, 0 } +, { "Deprecated", MarkType::kDeprecated, R_Y, E_N, M_CS | M_MDCM | M_E } , { "Description", MarkType::kDescription, R_Y, E_N, M(Example) | M(NoExample) } -, { "Doxygen", MarkType::kDoxygen, R_Y, E_N, 0 } +, { "Details", MarkType::kDetails, R_N, E_N, M(Const) } , { "Duration", MarkType::kDuration, R_N, E_N, M(Example) | M(NoExample) } -, { "Enum", MarkType::kEnum, R_Y, E_O, M_CSST | M(Root) } -, { "EnumClass", MarkType::kEnumClass, R_Y, E_O, M_CSST | M(Root) } -, { "Example", MarkType::kExample, R_O, E_N, M_CSST | M_E | M(Method) | M(Const) | M(Define) } -, { "Experimental", MarkType::kExperimental, R_Y, E_N, 0 } -, { "External", MarkType::kExternal, R_Y, E_N, M(Root) } -, { "File", MarkType::kFile, R_N, E_N, M(Track) } -, { "Formula", MarkType::kFormula, R_F, E_N, - M(Column) | M_E | M_ST | M(Member) | M(Method) | M_D } +, { "Enum", MarkType::kEnum, R_Y, E_O, M_CSST } +, { "EnumClass", MarkType::kEnumClass, R_Y, E_O, M_CSST } +, { "Example", MarkType::kExample, R_O, E_N, M_CSST | M_E | M_MD } +, { "Experimental", MarkType::kExperimental, R_Y, E_N, M_CS | M_MDCM | M_E } +, { "External", MarkType::kExternal, R_Y, E_N, 0 } +, { "Formula", MarkType::kFormula, R_F, E_N, M(Column) | M(Description) + | M_E | M_ST | M_MDCM } , { "Function", MarkType::kFunction, R_O, E_N, M(Example) | M(NoExample) } , { "Height", MarkType::kHeight, R_N, E_N, M(Example) | M(NoExample) } -, { "Illustration", MarkType::kIllustration, R_N, E_N, M(Subtopic) } +, { "Illustration", MarkType::kIllustration, R_N, E_N, M_CSST | M_MD } , { "Image", MarkType::kImage, R_N, E_N, M(Example) | M(NoExample) } , { "In", MarkType::kIn, R_N, E_N, M_CSST | M_E | M(Method) | M(Typedef) } , { "Legend", MarkType::kLegend, R_Y, E_N, M(Table) } @@ -123,32 +160,31 @@ BmhParser::MarkProps BmhParser::kMarkProps[] = { , { "", MarkType::kMarkChar, R_N, E_N, 0 } , { "Member", MarkType::kMember, R_Y, E_N, M_CSST } , { "Method", MarkType::kMethod, R_Y, E_Y, M_CSST } -, { "NoExample", MarkType::kNoExample, R_N, E_N, M_CSST | M_E | M(Method) | M(Const) | M(Define) } +, { "NoExample", MarkType::kNoExample, R_N, E_N, M_CSST | M_E | M_MD } +, { "NoJustify", MarkType::kNoJustify, R_N, E_N, M(Const) | M(Member) } , { "Outdent", MarkType::kOutdent, R_N, E_N, M(Code) } , { "Param", MarkType::kParam, R_Y, E_N, M(Method) | M(Define) } , { "PhraseDef", MarkType::kPhraseDef, R_Y, E_N, M(Subtopic) } -, { "", MarkType::kPhraseRef, R_Y, E_N, 0 } +, { "", MarkType::kPhraseParam, R_Y, E_N, 0 } +, { "", MarkType::kPhraseRef, R_N, E_N, 0 } , { "Platform", MarkType::kPlatform, R_N, E_N, M(Example) | M(NoExample) } , { "Populate", MarkType::kPopulate, R_N, E_N, M(Subtopic) } -, { "Private", MarkType::kPrivate, R_N, E_N, 0 } +, { "Private", MarkType::kPrivate, R_Y, E_N, M_CSST | M_MDCM | M_E } , { "Return", MarkType::kReturn, R_Y, E_N, M(Method) } -, { "", MarkType::kRoot, R_Y, E_N, 0 } , { "", MarkType::kRow, R_Y, E_N, M(Table) | M(List) } -, { "SeeAlso", MarkType::kSeeAlso, R_C, E_N, M_CSST | M_E | M(Method) | M(Define) | M(Typedef) } +, { "SeeAlso", MarkType::kSeeAlso, R_C, E_N, M_CSST | M_E | M_MD | M(Typedef) } , { "Set", MarkType::kSet, R_N, E_N, M(Example) | M(NoExample) } , { "StdOut", MarkType::kStdOut, R_N, E_N, M(Example) | M(NoExample) } -, { "Struct", MarkType::kStruct, R_Y, E_O, M(Class) | M(Root) | M_ST } +, { "Struct", MarkType::kStruct, R_Y, E_O, M(Class) | M_ST } , { "Substitute", MarkType::kSubstitute, R_N, E_N, M_ST } , { "Subtopic", MarkType::kSubtopic, R_Y, E_Y, M_CSST } , { "Table", MarkType::kTable, R_Y, E_N, M(Method) | M_CSST | M_E } -, { "Template", MarkType::kTemplate, R_Y, E_N, 0 } +, { "Template", MarkType::kTemplate, R_Y, E_N, M_CSST } , { "", MarkType::kText, R_N, E_N, 0 } -, { "Time", MarkType::kTime, R_Y, E_N, M(Track) } , { "ToDo", MarkType::kToDo, R_N, E_N, 0 } -, { "Topic", MarkType::kTopic, R_Y, E_Y, M_CS | M(Root) | M(Topic) } -, { "Track", MarkType::kTrack, R_Y, E_N, M_E | M_ST } -, { "Typedef", MarkType::kTypedef, R_Y, E_N, M(Class) | M_ST } -, { "", MarkType::kUnion, R_Y, E_N, 0 } +, { "Topic", MarkType::kTopic, R_Y, E_Y, 0 } +, { "Typedef", MarkType::kTypedef, R_Y, E_N, M_CSST | M_E } +, { "Union", MarkType::kUnion, R_Y, E_N, M_CSST } , { "Volatile", MarkType::kVolatile, R_N, E_N, M(StdOut) } , { "Width", MarkType::kWidth, R_N, E_N, M(Example) | M(NoExample) } }; @@ -163,6 +199,7 @@ BmhParser::MarkProps BmhParser::kMarkProps[] = { #undef M_CSST #undef M_ST #undef M_CS +#undef M_MCD #undef M_D #undef M @@ -438,18 +475,46 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy fParent->fChildren.push_back(definition); } break; + } else if (MarkType::kPhraseDef == markType) { + bool hasParams = '(' == this->next(); + fMarkup.emplace_front(markType, defStart, fLineCount, fParent, fMC); + definition = &fMarkup.front(); + definition->fName = typeNameBuilder[0]; + definition->fFiddle = fParent->fFiddle; + definition->fContentStart = fChar; + if (hasParams) { + char lastChar; + do { + const char* subEnd = this->anyOf(",)\n"); + if (!subEnd || '\n' == *subEnd) { + return this->reportError<bool>("unexpected phrase list end"); + } + fMarkup.emplace_front(MarkType::kPhraseParam, fChar, fLineCount, fParent, + fMC); + Definition* phraseParam = &fMarkup.front(); + phraseParam->fContentStart = fChar; + phraseParam->fContentEnd = subEnd; + phraseParam->fName = string(fChar, subEnd - fChar); + definition->fChildren.push_back(phraseParam); + this->skipTo(subEnd); + lastChar = this->next(); + phraseParam->fTerminator = fChar; + } while (')' != lastChar); + this->skipWhiteSpace(); + definition->fContentStart = fChar; + } + this->setAsParent(definition); + break; } // not one-liners case MarkType::kCode: case MarkType::kExample: - case MarkType::kExperimental: case MarkType::kFormula: case MarkType::kFunction: case MarkType::kLegend: case MarkType::kList: case MarkType::kPrivate: case MarkType::kTable: - case MarkType::kTrack: if (hasEnd) { definition = fParent; if (markType != fParent->fMarkType) { @@ -502,21 +567,22 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy case MarkType::kAnchor: case MarkType::kBug: case MarkType::kDeprecated: + case MarkType::kDetails: case MarkType::kDuration: - case MarkType::kFile: + case MarkType::kExperimental: case MarkType::kHeight: case MarkType::kIllustration: case MarkType::kImage: case MarkType::kIn: case MarkType::kLine: case MarkType::kLiteral: + case MarkType::kNoJustify: case MarkType::kOutdent: case MarkType::kPlatform: case MarkType::kPopulate: case MarkType::kSeeAlso: case MarkType::kSet: case MarkType::kSubstitute: - case MarkType::kTime: case MarkType::kVolatile: case MarkType::kWidth: // todo : add check disallowing children? @@ -569,16 +635,37 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy } fMarkup.emplace_front(MarkType::kText, start, fLineCount, definition, fMC); Definition* text = &fMarkup.front(); + if (!islower(start[0]) && (!isdigit(start[0]) + || MarkType::kConst != definition->fParent->fMarkType)) { + return this->reportError<bool>("expect lower case start"); + } + string contents = string(start, end - start); + if (string::npos != contents.find('.')) { + return this->reportError<bool>("expect phrase, not sentence"); + } + size_t firstSpace = contents.find(' '); + if (string::npos == firstSpace || 0 == firstSpace || 's' != start[firstSpace - 1]) { + if (MarkType::kMethod == fParent->fMarkType && "experimental" != contents + && "incomplete" != contents) { + return this->reportError<bool>( "expect phrase in third person present" + " tense (1st word should end in 's'"); + } + } text->fContentStart = start; text->fContentEnd = end; text->fTerminator = fChar; definition->fContentEnd = text->fContentEnd; definition->fTerminator = fChar; definition->fChildren.emplace_back(text); - } else if (MarkType::kDeprecated == markType) { + } else if (IncompleteAllowed(markType)) { this->skipSpace(); fParent->fDeprecated = true; - fParent->fToBeDeprecated = this->skipExact("soon"); + fParent->fDetails = + this->skipExact("soon") ? Definition::Details::kSoonToBe_Deprecated : + this->skipExact("testing") ? Definition::Details::kTestingOnly_Experiment : + this->skipExact("do not use") ? Definition::Details::kDoNotUse_Experiement : + this->skipExact("not ready") ? Definition::Details::kNotReady_Experiment : + Definition::Details::kNone; this->skipSpace(); if ('\n' != this->peek()) { return this->reportError<bool>("unexpected text after #Deprecated"); @@ -1210,8 +1297,8 @@ bool BmhParser::findDefinitions() { const char* defStart = fChar - 1; MarkType markType = this->getMarkType(MarkLookup::kRequire); bool hasEnd = this->hasEndToken(); - if (!hasEnd) { - MarkType parentType = fParent ? fParent->fMarkType : MarkType::kRoot; + if (!hasEnd && fParent) { + MarkType parentType = fParent->fMarkType; uint64_t parentMask = kMarkProps[(int) markType].fParentMask; if (parentMask && !(parentMask & (1LL << (int) parentType))) { return this->reportError<bool>("invalid parent"); @@ -1298,8 +1385,24 @@ bool BmhParser::findDefinitions() { const char* phraseNameStart = fChar; this->skipPhraseName(); string phraseKey = string(phraseNameStart, fChar - phraseNameStart); - if (fMC != this->next()) { - return this->reportError<bool>("expect # after phrase-name"); + char delimiter = this->next(); + vector<string> params; + vector<const char*> paramsLoc; + if (fMC != delimiter) { + if ('(' != delimiter) { + return this->reportError<bool>("expect # after phrase name"); + } + // phrase may take comma delimited parameter list + do { + const char* subEnd = this->anyOf(",)\n"); + if (!subEnd || '\n' == *subEnd) { + return this->reportError<bool>("unexpected phrase list end"); + } + params.push_back(string(fChar, subEnd - fChar)); + paramsLoc.push_back(fChar); + this->skipTo(subEnd); + + } while (')' != this->next()); } const char* start = phraseNameStart; SkASSERT('#' == start[-1]); @@ -1309,12 +1412,24 @@ bool BmhParser::findDefinitions() { } fMarkup.emplace_front(MarkType::kPhraseRef, start, fLineCount, fParent, fMC); Definition* markChar = &fMarkup.front(); + this->skipExact("#"); markChar->fContentStart = fChar; - this->skipToEndBracket('\n'); markChar->fContentEnd = fChar; markChar->fTerminator = fChar; markChar->fName = phraseKey; fParent->fChildren.push_back(markChar); + int paramLocIndex = 0; + for (auto param : params) { + const char* paramLoc = paramsLoc[paramLocIndex++]; + fMarkup.emplace_front(MarkType::kPhraseParam, paramLoc, fLineCount, fParent, + fMC); + Definition* phraseParam = &fMarkup.front(); + phraseParam->fContentStart = paramLoc; + phraseParam->fContentEnd = paramLoc + param.length(); + phraseParam->fTerminator = paramLoc + param.length(); + phraseParam->fName = param; + markChar->fChildren.push_back(phraseParam); + } } } char nextChar = this->next(); @@ -1384,13 +1499,14 @@ bool HackParser::hackFiles() { SkASSERT(!root->fParent); fStart = root->fStart; fChar = fStart; - fClassesAndStructs = nullptr; + fClasses = nullptr; fConstants = nullptr; fConstructors = nullptr; fMemberFunctions = nullptr; fMembers = nullptr; fOperators = nullptr; fRelatedFunctions = nullptr; + fStructs = nullptr; this->topicIter(root); fprintf(fOut, "%.*s", (int) (fEnd - fChar), fChar); fclose(fOut); @@ -1442,31 +1558,35 @@ string HackParser::searchTable(const Definition* tableHolder, const Definition* // returns true if topic has method void HackParser::topicIter(const Definition* topic) { - if (string::npos != topic->fName.find(MdOut::kClassesAndStructs)) { - SkASSERT(!fClassesAndStructs); - fClassesAndStructs = topic; + if (string::npos != topic->fName.find(SubtopicKeys::kClasses)) { + SkASSERT(!fClasses); + fClasses = topic; + } + if (string::npos != topic->fName.find(SubtopicKeys::kStructs)) { + SkASSERT(!fStructs); + fStructs = topic; } - if (string::npos != topic->fName.find(MdOut::kConstants)) { + if (string::npos != topic->fName.find(SubtopicKeys::kConstants)) { SkASSERT(!fConstants); fConstants = topic; } - if (string::npos != topic->fName.find(MdOut::kConstructors)) { + if (string::npos != topic->fName.find(SubtopicKeys::kConstructors)) { SkASSERT(!fConstructors); fConstructors = topic; } - if (string::npos != topic->fName.find(MdOut::kMemberFunctions)) { + if (string::npos != topic->fName.find(SubtopicKeys::kMemberFunctions)) { SkASSERT(!fMemberFunctions); fMemberFunctions = topic; } - if (string::npos != topic->fName.find(MdOut::kMembers)) { + if (string::npos != topic->fName.find(SubtopicKeys::kMembers)) { SkASSERT(!fMembers); fMembers = topic; } - if (string::npos != topic->fName.find(MdOut::kOperators)) { + if (string::npos != topic->fName.find(SubtopicKeys::kOperators)) { SkASSERT(!fOperators); fOperators = topic; } - if (string::npos != topic->fName.find(MdOut::kRelatedFunctions)) { + if (string::npos != topic->fName.find(SubtopicKeys::kRelatedFunctions)) { SkASSERT(!fRelatedFunctions); fRelatedFunctions = topic; } @@ -1539,8 +1659,11 @@ void HackParser::topicIter(const Definition* topic) { this->topicIter(child); break; case MarkType::kStruct: + this->addOneLiner(fStructs, child, hasLine, false); + this->topicIter(child); + break; case MarkType::kClass: - this->addOneLiner(fClassesAndStructs, child, hasLine, false); + this->addOneLiner(fClasses, child, hasLine, false); this->topicIter(child); break; case MarkType::kEnum: @@ -1822,6 +1945,7 @@ void TextParser::reportError(const char* errorStr) const { } void TextParser::reportWarning(const char* errorStr) const { + SkASSERT(fLine < fEnd); TextParser err(fFileName, fLine, fEnd, fLineCount); size_t lineLen = this->lineLength(); ptrdiff_t spaces = fChar - fLine; @@ -1892,7 +2016,13 @@ string TextParser::typedefName() { do { this->skipToWhiteSpace(); if (fChar < end && isspace(fChar[0])) { + const char* whiteStart = fChar; this->skipWhiteSpace(); + // FIXME: test should be for fMC + if ('#' == fChar[0]) { + end = whiteStart; + break; + } lastWord = fChar; } else { break; @@ -2051,8 +2181,6 @@ vector<string> BmhParser::typeName(MarkType markType, bool* checkEnd) { break; case MarkType::kCode: case MarkType::kDescription: - case MarkType::kDoxygen: - case MarkType::kExperimental: case MarkType::kExternal: case MarkType::kFormula: case MarkType::kFunction: @@ -2060,7 +2188,6 @@ vector<string> BmhParser::typeName(MarkType markType, bool* checkEnd) { case MarkType::kList: case MarkType::kNoExample: case MarkType::kPrivate: - case MarkType::kTrack: this->skipNoName(); break; case MarkType::kLine: @@ -2071,13 +2198,15 @@ vector<string> BmhParser::typeName(MarkType markType, bool* checkEnd) { case MarkType::kBug: // fixme: expect number case MarkType::kDefinedBy: case MarkType::kDeprecated: + case MarkType::kDetails: case MarkType::kDuration: - case MarkType::kFile: + case MarkType::kExperimental: case MarkType::kHeight: case MarkType::kIllustration: case MarkType::kImage: case MarkType::kIn: case MarkType::kLiteral: + case MarkType::kNoJustify: case MarkType::kOutdent: case MarkType::kPlatform: case MarkType::kPopulate: @@ -2085,7 +2214,6 @@ vector<string> BmhParser::typeName(MarkType markType, bool* checkEnd) { case MarkType::kSeeAlso: case MarkType::kSet: case MarkType::kSubstitute: - case MarkType::kTime: case MarkType::kToDo: case MarkType::kVolatile: case MarkType::kWidth: @@ -2104,12 +2232,22 @@ vector<string> BmhParser::typeName(MarkType markType, bool* checkEnd) { builder = this->typedefName(); break; case MarkType::kParam: - case MarkType::kPhraseDef: // fixme: expect camelCase for param builder = this->word("", ""); this->skipSpace(); *checkEnd = false; break; + case MarkType::kPhraseDef: { + const char* nameEnd = this->anyOf("(\n"); + builder = string(fChar, nameEnd - fChar); + this->skipLower(); + if (fChar != nameEnd) { + this->reportError("expect lower case only"); + break; + } + this->skipTo(nameEnd); + *checkEnd = false; + } break; case MarkType::kTable: this->skipNoName(); break; // unnamed @@ -2516,6 +2654,7 @@ int main(int argc, char** const argv) { } MdOut mdOut(bmhParser); mdOut.fDebugOut = FLAGS_stdout; + mdOut.fValidate = FLAGS_validate; if (!FLAGS_bmh.isEmpty() && mdOut.buildReferences(includeParser, FLAGS_bmh[0], FLAGS_ref[0])) { bmhParser.fWroteOut = true; @@ -2523,6 +2662,9 @@ int main(int argc, char** const argv) { if (!FLAGS_status.isEmpty() && mdOut.buildStatus(FLAGS_status[0], FLAGS_ref[0])) { bmhParser.fWroteOut = true; } + if (FLAGS_validate) { + mdOut.checkAnchors(); + } } if (!done && !FLAGS_spellcheck.isEmpty() && FLAGS_examples.isEmpty()) { if (!FLAGS_bmh.isEmpty()) { |