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