blob: 95daa7e3f80976d131766ca9439fece8b36dec52 [file] [log] [blame]
Dmitri Gribenko2d44d772012-06-26 20:39:18 +00001//===--- 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"
Dmitri Gribenkoaa580812012-08-09 00:03:17 +000011#include "clang/AST/CommentCommandTraits.h"
Dmitri Gribenko55e18082012-06-29 18:19:20 +000012#include "llvm/ADT/StringSwitch.h"
Dmitri Gribenko2d44d772012-06-26 20:39:18 +000013
14namespace clang {
15namespace comments {
16
Dmitri Gribenkod558b522012-06-28 01:38:21 +000017namespace {
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +000018inline bool isWhitespace(char C) {
19 return C == ' ' || C == '\n' || C == '\r' ||
20 C == '\t' || C == '\f' || C == '\v';
21}
22
Dmitri Gribenkod558b522012-06-28 01:38:21 +000023/// Convert all whitespace into spaces, remove leading and trailing spaces,
24/// compress multiple spaces into one.
25void cleanupBrief(std::string &S) {
26 bool PrevWasSpace = true;
27 std::string::iterator O = S.begin();
28 for (std::string::iterator I = S.begin(), E = S.end();
29 I != E; ++I) {
30 const char C = *I;
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +000031 if (isWhitespace(C)) {
Dmitri Gribenkod558b522012-06-28 01:38:21 +000032 if (!PrevWasSpace) {
33 *O++ = ' ';
34 PrevWasSpace = true;
35 }
36 continue;
37 } else {
38 *O++ = C;
39 PrevWasSpace = false;
40 }
41 }
42 if (O != S.begin() && *(O - 1) == ' ')
43 --O;
44
45 S.resize(O - S.begin());
46}
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +000047
48bool isWhitespace(StringRef Text) {
49 for (StringRef::const_iterator I = Text.begin(), E = Text.end();
50 I != E; ++I) {
51 if (!isWhitespace(*I))
52 return false;
53 }
54 return true;
55}
Dmitri Gribenkod558b522012-06-28 01:38:21 +000056} // unnamed namespace
57
Dmitri Gribenkoaa580812012-08-09 00:03:17 +000058BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
59 L(L), Traits(Traits) {
60 // Get lookahead token.
61 ConsumeToken();
62}
63
Dmitri Gribenko2d44d772012-06-26 20:39:18 +000064std::string BriefParser::Parse() {
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000065 std::string FirstParagraphOrBrief;
66 std::string ReturnsParagraph;
Dmitri Gribenko2d44d772012-06-26 20:39:18 +000067 bool InFirstParagraph = true;
68 bool InBrief = false;
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000069 bool InReturns = false;
Dmitri Gribenko2d44d772012-06-26 20:39:18 +000070
71 while (Tok.isNot(tok::eof)) {
72 if (Tok.is(tok::text)) {
Dmitri Gribenkoc0b83242012-06-27 01:17:34 +000073 if (InFirstParagraph || InBrief)
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000074 FirstParagraphOrBrief += Tok.getText();
75 else if (InReturns)
76 ReturnsParagraph += Tok.getText();
Dmitri Gribenko2d44d772012-06-26 20:39:18 +000077 ConsumeToken();
78 continue;
79 }
80
Dmitri Gribenkof199b9c2012-06-28 00:01:41 +000081 if (Tok.is(tok::command)) {
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +000082 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
83 if (Info->IsBriefCommand) {
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000084 FirstParagraphOrBrief.clear();
Dmitri Gribenkof199b9c2012-06-28 00:01:41 +000085 InBrief = true;
86 ConsumeToken();
87 continue;
88 }
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +000089 if (Info->IsReturnsCommand) {
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000090 InReturns = true;
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +000091 InBrief = false;
92 InFirstParagraph = false;
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000093 ReturnsParagraph += "Returns ";
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +000094 ConsumeToken();
95 continue;
Dmitri Gribenko72021ff2012-07-20 17:01:34 +000096 }
Dmitri Gribenko55e18082012-06-29 18:19:20 +000097 // Block commands implicitly start a new paragraph.
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +000098 if (Info->IsBlockCommand) {
Dmitri Gribenkof199b9c2012-06-28 00:01:41 +000099 // We found an implicit paragraph end.
100 InFirstParagraph = false;
Dmitri Gribenko57aceb22012-07-03 18:10:20 +0000101 if (InBrief)
Dmitri Gribenkof199b9c2012-06-28 00:01:41 +0000102 break;
Dmitri Gribenkof199b9c2012-06-28 00:01:41 +0000103 }
Dmitri Gribenko2d44d772012-06-26 20:39:18 +0000104 }
105
106 if (Tok.is(tok::newline)) {
Dmitri Gribenkoc0b83242012-06-27 01:17:34 +0000107 if (InFirstParagraph || InBrief)
Dmitri Gribenko72021ff2012-07-20 17:01:34 +0000108 FirstParagraphOrBrief += ' ';
109 else if (InReturns)
110 ReturnsParagraph += ' ';
Dmitri Gribenko2d44d772012-06-26 20:39:18 +0000111 ConsumeToken();
112
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +0000113 // If the next token is a whitespace only text, ignore it. Thus we allow
114 // two paragraphs to be separated by line that has only whitespace in it.
115 //
116 // We don't need to add a space to the parsed text because we just added
117 // a space for the newline.
118 if (Tok.is(tok::text)) {
119 if (isWhitespace(Tok.getText()))
120 ConsumeToken();
121 }
122
Dmitri Gribenko2d44d772012-06-26 20:39:18 +0000123 if (Tok.is(tok::newline)) {
124 ConsumeToken();
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +0000125 // We found a paragraph end. This ends the brief description if
126 // \\brief command or its equivalent was explicitly used.
127 // Stop scanning text because an explicit \\brief paragraph is the
128 // preffered one.
Dmitri Gribenko57aceb22012-07-03 18:10:20 +0000129 if (InBrief)
Dmitri Gribenkof199b9c2012-06-28 00:01:41 +0000130 break;
Dmitri Gribenko0ac4ec72012-08-21 21:15:34 +0000131 // End first paragraph if we found some non-whitespace text.
132 if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
133 InFirstParagraph = false;
134 // End the \\returns paragraph because we found the paragraph end.
135 InReturns = false;
Dmitri Gribenko2d44d772012-06-26 20:39:18 +0000136 }
137 continue;
138 }
139
140 // We didn't handle this token, so just drop it.
141 ConsumeToken();
142 }
143
Dmitri Gribenko72021ff2012-07-20 17:01:34 +0000144 cleanupBrief(FirstParagraphOrBrief);
145 if (!FirstParagraphOrBrief.empty())
146 return FirstParagraphOrBrief;
147
148 cleanupBrief(ReturnsParagraph);
149 return ReturnsParagraph;
Dmitri Gribenko2d44d772012-06-26 20:39:18 +0000150}
151
Dmitri Gribenko2d44d772012-06-26 20:39:18 +0000152} // end namespace comments
153} // end namespace clang
154
155