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