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