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       .Default(false);
52 }
53 } // unnamed namespace
54 
55 std::string BriefParser::Parse() {
56   std::string Paragraph;
57   bool InFirstParagraph = true;
58   bool InBrief = false;
59 
60   while (Tok.isNot(tok::eof)) {
61     if (Tok.is(tok::text)) {
62       if (InFirstParagraph || InBrief)
63         Paragraph += Tok.getText();
64       ConsumeToken();
65       continue;
66     }
67 
68     if (Tok.is(tok::command)) {
69       StringRef Name = Tok.getCommandName();
70       if (Name == "brief" || Name == "short") {
71         Paragraph.clear();
72         InBrief = true;
73         ConsumeToken();
74         continue;
75       }
76       // Block commands implicitly start a new paragraph.
77       if (isBlockCommand(Name)) {
78         // We found an implicit paragraph end.
79         InFirstParagraph = false;
80         if (InBrief)
81           break;
82       }
83     }
84 
85     if (Tok.is(tok::newline)) {
86       if (InFirstParagraph || InBrief)
87         Paragraph += ' ';
88       ConsumeToken();
89 
90       if (Tok.is(tok::newline)) {
91         ConsumeToken();
92         // We found a paragraph end.
93         InFirstParagraph = false;
94         if (InBrief)
95           break;
96       }
97       continue;
98     }
99 
100     // We didn't handle this token, so just drop it.
101     ConsumeToken();
102   }
103 
104   cleanupBrief(Paragraph);
105   return Paragraph;
106 }
107 
108 BriefParser::BriefParser(Lexer &L) : L(L)
109 {
110   // Get lookahead token.
111   ConsumeToken();
112 }
113 
114 } // end namespace comments
115 } // end namespace clang
116 
117 
118