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 "llvm/ADT/StringSwitch.h" 12 13 namespace clang { 14 namespace comments { 15 16 namespace { 17 /// Convert all whitespace into spaces, remove leading and trailing spaces, 18 /// compress multiple spaces into one. 19 void cleanupBrief(std::string &S) { 20 bool PrevWasSpace = true; 21 std::string::iterator O = S.begin(); 22 for (std::string::iterator I = S.begin(), E = S.end(); 23 I != E; ++I) { 24 const char C = *I; 25 if (C == ' ' || C == '\n' || C == '\r' || 26 C == '\t' || C == '\v' || C == '\f') { 27 if (!PrevWasSpace) { 28 *O++ = ' '; 29 PrevWasSpace = true; 30 } 31 continue; 32 } else { 33 *O++ = C; 34 PrevWasSpace = false; 35 } 36 } 37 if (O != S.begin() && *(O - 1) == ' ') 38 --O; 39 40 S.resize(O - S.begin()); 41 } 42 43 bool isBlockCommand(StringRef Name) { 44 return llvm::StringSwitch<bool>(Name) 45 .Cases("brief", "short", true) 46 .Cases("result", "return", "returns", true) 47 .Cases("author", "authors", true) 48 .Case("pre", true) 49 .Case("post", true) 50 .Cases("param", "arg", true) 51 .Case("tparam", true) 52 .Default(false); 53 } 54 } // unnamed namespace 55 56 std::string BriefParser::Parse() { 57 std::string FirstParagraphOrBrief; 58 std::string ReturnsParagraph; 59 bool InFirstParagraph = true; 60 bool InBrief = false; 61 bool InReturns = false; 62 63 while (Tok.isNot(tok::eof)) { 64 if (Tok.is(tok::text)) { 65 if (InFirstParagraph || InBrief) 66 FirstParagraphOrBrief += Tok.getText(); 67 else if (InReturns) 68 ReturnsParagraph += Tok.getText(); 69 ConsumeToken(); 70 continue; 71 } 72 73 if (Tok.is(tok::command)) { 74 StringRef Name = Tok.getCommandName(); 75 if (Name == "brief" || Name == "short") { 76 FirstParagraphOrBrief.clear(); 77 InBrief = true; 78 ConsumeToken(); 79 continue; 80 } 81 if (Name == "result" || Name == "return" || Name == "returns") { 82 InReturns = true; 83 ReturnsParagraph += "Returns "; 84 } 85 // Block commands implicitly start a new paragraph. 86 if (isBlockCommand(Name)) { 87 // We found an implicit paragraph end. 88 InFirstParagraph = false; 89 if (InBrief) 90 break; 91 } 92 } 93 94 if (Tok.is(tok::newline)) { 95 if (InFirstParagraph || InBrief) 96 FirstParagraphOrBrief += ' '; 97 else if (InReturns) 98 ReturnsParagraph += ' '; 99 ConsumeToken(); 100 101 if (Tok.is(tok::newline)) { 102 ConsumeToken(); 103 // We found a paragraph end. 104 InFirstParagraph = false; 105 InReturns = false; 106 if (InBrief) 107 break; 108 } 109 continue; 110 } 111 112 // We didn't handle this token, so just drop it. 113 ConsumeToken(); 114 } 115 116 cleanupBrief(FirstParagraphOrBrief); 117 if (!FirstParagraphOrBrief.empty()) 118 return FirstParagraphOrBrief; 119 120 cleanupBrief(ReturnsParagraph); 121 return ReturnsParagraph; 122 } 123 124 BriefParser::BriefParser(Lexer &L) : L(L) { 125 // Get lookahead token. 126 ConsumeToken(); 127 } 128 129 } // end namespace comments 130 } // end namespace clang 131 132 133