1*67e74705SXin Li //===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===// 2*67e74705SXin Li // 3*67e74705SXin Li // The LLVM Compiler Infrastructure 4*67e74705SXin Li // 5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source 6*67e74705SXin Li // License. See LICENSE.TXT for details. 7*67e74705SXin Li // 8*67e74705SXin Li //===----------------------------------------------------------------------===// 9*67e74705SXin Li 10*67e74705SXin Li #include "clang/AST/CommentBriefParser.h" 11*67e74705SXin Li #include "clang/AST/CommentCommandTraits.h" 12*67e74705SXin Li #include "llvm/ADT/StringSwitch.h" 13*67e74705SXin Li 14*67e74705SXin Li namespace clang { 15*67e74705SXin Li namespace comments { 16*67e74705SXin Li 17*67e74705SXin Li namespace { isWhitespace(char C)18*67e74705SXin Liinline bool isWhitespace(char C) { 19*67e74705SXin Li return C == ' ' || C == '\n' || C == '\r' || 20*67e74705SXin Li C == '\t' || C == '\f' || C == '\v'; 21*67e74705SXin Li } 22*67e74705SXin Li 23*67e74705SXin Li /// Convert all whitespace into spaces, remove leading and trailing spaces, 24*67e74705SXin Li /// compress multiple spaces into one. cleanupBrief(std::string & S)25*67e74705SXin Livoid cleanupBrief(std::string &S) { 26*67e74705SXin Li bool PrevWasSpace = true; 27*67e74705SXin Li std::string::iterator O = S.begin(); 28*67e74705SXin Li for (std::string::iterator I = S.begin(), E = S.end(); 29*67e74705SXin Li I != E; ++I) { 30*67e74705SXin Li const char C = *I; 31*67e74705SXin Li if (isWhitespace(C)) { 32*67e74705SXin Li if (!PrevWasSpace) { 33*67e74705SXin Li *O++ = ' '; 34*67e74705SXin Li PrevWasSpace = true; 35*67e74705SXin Li } 36*67e74705SXin Li continue; 37*67e74705SXin Li } else { 38*67e74705SXin Li *O++ = C; 39*67e74705SXin Li PrevWasSpace = false; 40*67e74705SXin Li } 41*67e74705SXin Li } 42*67e74705SXin Li if (O != S.begin() && *(O - 1) == ' ') 43*67e74705SXin Li --O; 44*67e74705SXin Li 45*67e74705SXin Li S.resize(O - S.begin()); 46*67e74705SXin Li } 47*67e74705SXin Li isWhitespace(StringRef Text)48*67e74705SXin Libool isWhitespace(StringRef Text) { 49*67e74705SXin Li for (StringRef::const_iterator I = Text.begin(), E = Text.end(); 50*67e74705SXin Li I != E; ++I) { 51*67e74705SXin Li if (!isWhitespace(*I)) 52*67e74705SXin Li return false; 53*67e74705SXin Li } 54*67e74705SXin Li return true; 55*67e74705SXin Li } 56*67e74705SXin Li } // unnamed namespace 57*67e74705SXin Li BriefParser(Lexer & L,const CommandTraits & Traits)58*67e74705SXin LiBriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : 59*67e74705SXin Li L(L), Traits(Traits) { 60*67e74705SXin Li // Get lookahead token. 61*67e74705SXin Li ConsumeToken(); 62*67e74705SXin Li } 63*67e74705SXin Li Parse()64*67e74705SXin Listd::string BriefParser::Parse() { 65*67e74705SXin Li std::string FirstParagraphOrBrief; 66*67e74705SXin Li std::string ReturnsParagraph; 67*67e74705SXin Li bool InFirstParagraph = true; 68*67e74705SXin Li bool InBrief = false; 69*67e74705SXin Li bool InReturns = false; 70*67e74705SXin Li 71*67e74705SXin Li while (Tok.isNot(tok::eof)) { 72*67e74705SXin Li if (Tok.is(tok::text)) { 73*67e74705SXin Li if (InFirstParagraph || InBrief) 74*67e74705SXin Li FirstParagraphOrBrief += Tok.getText(); 75*67e74705SXin Li else if (InReturns) 76*67e74705SXin Li ReturnsParagraph += Tok.getText(); 77*67e74705SXin Li ConsumeToken(); 78*67e74705SXin Li continue; 79*67e74705SXin Li } 80*67e74705SXin Li 81*67e74705SXin Li if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) { 82*67e74705SXin Li const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); 83*67e74705SXin Li if (Info->IsBriefCommand) { 84*67e74705SXin Li FirstParagraphOrBrief.clear(); 85*67e74705SXin Li InBrief = true; 86*67e74705SXin Li ConsumeToken(); 87*67e74705SXin Li continue; 88*67e74705SXin Li } 89*67e74705SXin Li if (Info->IsReturnsCommand) { 90*67e74705SXin Li InReturns = true; 91*67e74705SXin Li InBrief = false; 92*67e74705SXin Li InFirstParagraph = false; 93*67e74705SXin Li ReturnsParagraph += "Returns "; 94*67e74705SXin Li ConsumeToken(); 95*67e74705SXin Li continue; 96*67e74705SXin Li } 97*67e74705SXin Li // Block commands implicitly start a new paragraph. 98*67e74705SXin Li if (Info->IsBlockCommand) { 99*67e74705SXin Li // We found an implicit paragraph end. 100*67e74705SXin Li InFirstParagraph = false; 101*67e74705SXin Li if (InBrief) 102*67e74705SXin Li break; 103*67e74705SXin Li } 104*67e74705SXin Li } 105*67e74705SXin Li 106*67e74705SXin Li if (Tok.is(tok::newline)) { 107*67e74705SXin Li if (InFirstParagraph || InBrief) 108*67e74705SXin Li FirstParagraphOrBrief += ' '; 109*67e74705SXin Li else if (InReturns) 110*67e74705SXin Li ReturnsParagraph += ' '; 111*67e74705SXin Li ConsumeToken(); 112*67e74705SXin Li 113*67e74705SXin Li // If the next token is a whitespace only text, ignore it. Thus we allow 114*67e74705SXin Li // two paragraphs to be separated by line that has only whitespace in it. 115*67e74705SXin Li // 116*67e74705SXin Li // We don't need to add a space to the parsed text because we just added 117*67e74705SXin Li // a space for the newline. 118*67e74705SXin Li if (Tok.is(tok::text)) { 119*67e74705SXin Li if (isWhitespace(Tok.getText())) 120*67e74705SXin Li ConsumeToken(); 121*67e74705SXin Li } 122*67e74705SXin Li 123*67e74705SXin Li if (Tok.is(tok::newline)) { 124*67e74705SXin Li ConsumeToken(); 125*67e74705SXin Li // We found a paragraph end. This ends the brief description if 126*67e74705SXin Li // \\brief command or its equivalent was explicitly used. 127*67e74705SXin Li // Stop scanning text because an explicit \\brief paragraph is the 128*67e74705SXin Li // preffered one. 129*67e74705SXin Li if (InBrief) 130*67e74705SXin Li break; 131*67e74705SXin Li // End first paragraph if we found some non-whitespace text. 132*67e74705SXin Li if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief)) 133*67e74705SXin Li InFirstParagraph = false; 134*67e74705SXin Li // End the \\returns paragraph because we found the paragraph end. 135*67e74705SXin Li InReturns = false; 136*67e74705SXin Li } 137*67e74705SXin Li continue; 138*67e74705SXin Li } 139*67e74705SXin Li 140*67e74705SXin Li // We didn't handle this token, so just drop it. 141*67e74705SXin Li ConsumeToken(); 142*67e74705SXin Li } 143*67e74705SXin Li 144*67e74705SXin Li cleanupBrief(FirstParagraphOrBrief); 145*67e74705SXin Li if (!FirstParagraphOrBrief.empty()) 146*67e74705SXin Li return FirstParagraphOrBrief; 147*67e74705SXin Li 148*67e74705SXin Li cleanupBrief(ReturnsParagraph); 149*67e74705SXin Li return ReturnsParagraph; 150*67e74705SXin Li } 151*67e74705SXin Li 152*67e74705SXin Li } // end namespace comments 153*67e74705SXin Li } // end namespace clang 154*67e74705SXin Li 155*67e74705SXin Li 156