blob: 8dc1278e043d6eb39ddeed2116693eb365db7cf7 [file] [log] [blame]
Daniel Jasperf7935112012-12-03 18:12:45 +00001//===--- UnwrappedLineParser.cpp - Format C++ code ------------------------===//
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/// \file
11/// \brief This file contains the implementation of the UnwrappedLineParser,
12/// which turns a stream of tokens into UnwrappedLines.
13///
14/// This is EXPERIMENTAL code under heavy development. It is not in a state yet,
15/// where it can be used to format real code.
16///
17//===----------------------------------------------------------------------===//
18
19#include "UnwrappedLineParser.h"
20
21#include "llvm/Support/raw_ostream.h"
22
23namespace clang {
24namespace format {
25
26UnwrappedLineParser::UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr,
27 UnwrappedLineConsumer &Callback)
28 : GreaterStashed(false),
29 Lex(Lex),
30 SourceMgr(SourceMgr),
31 IdentTable(Lex.getLangOpts()),
32 Callback(Callback) {
33 Lex.SetKeepWhitespaceMode(true);
34}
35
36void UnwrappedLineParser::parse() {
37 parseToken();
38 parseLevel();
39}
40
41void UnwrappedLineParser::parseLevel() {
42 do {
43 switch (FormatTok.Tok.getKind()) {
44 case tok::hash:
45 parsePPDirective();
46 break;
47 case tok::comment:
48 parseComment();
49 break;
50 case tok::l_brace:
51 parseBlock();
52 addUnwrappedLine();
53 break;
54 case tok::r_brace:
55 return;
56 default:
57 parseStatement();
58 break;
59 }
60 } while (!eof());
61}
62
63void UnwrappedLineParser::parseBlock() {
64 nextToken();
65
66 // FIXME: Remove this hack to handle namespaces.
67 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
68
69 addUnwrappedLine();
70
71 if (!IsNamespace)
72 ++Line.Level;
73 parseLevel();
74 if (!IsNamespace)
75 --Line.Level;
76 assert(FormatTok.Tok.is(tok::r_brace) && "expected '}'");
77 nextToken();
78 if (FormatTok.Tok.is(tok::semi))
79 nextToken();
80}
81
82void UnwrappedLineParser::parsePPDirective() {
83 while (!eof()) {
84 nextToken();
85 if (FormatTok.NewlinesBefore > 0) {
86 addUnwrappedLine();
87 return;
88 }
89 }
90}
91
92void UnwrappedLineParser::parseComment() {
93 while (!eof()) {
94 nextToken();
95 if (FormatTok.NewlinesBefore > 0) {
96 addUnwrappedLine();
97 return;
98 }
99 }
100}
101
102void UnwrappedLineParser::parseStatement() {
103 if (FormatTok.Tok.is(tok::kw_public) || FormatTok.Tok.is(tok::kw_protected) ||
104 FormatTok.Tok.is(tok::kw_private)) {
105 parseAccessSpecifier();
106 return;
107 }
108 if (FormatTok.Tok.is(tok::kw_enum)) {
109 parseEnum();
110 return;
111 }
112 int TokenNumber = 0;
113 do {
114 ++TokenNumber;
115 switch (FormatTok.Tok.getKind()) {
116 case tok::semi:
117 nextToken();
118 addUnwrappedLine();
119 return;
120 case tok::l_paren:
121 parseParens();
122 break;
123 case tok::l_brace:
124 parseBlock();
125 addUnwrappedLine();
126 return;
127 case tok::kw_if:
128 parseIfThenElse();
129 return;
130 case tok::kw_do:
131 parseDoWhile();
132 return;
133 case tok::kw_switch:
134 parseSwitch();
135 return;
136 case tok::kw_default:
137 nextToken();
138 parseLabel();
139 return;
140 case tok::kw_case:
141 parseCaseLabel();
142 return;
143 case tok::raw_identifier:
144 nextToken();
145 break;
146 default:
147 nextToken();
148 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
149 parseLabel();
150 return;
151 }
152 break;
153 }
154 } while (!eof());
155}
156
157void UnwrappedLineParser::parseParens() {
158 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
159 nextToken();
160 do {
161 switch (FormatTok.Tok.getKind()) {
162 case tok::l_paren:
163 parseParens();
164 break;
165 case tok::r_paren:
166 nextToken();
167 return;
168 default:
169 nextToken();
170 break;
171 }
172 } while (!eof());
173}
174
175void UnwrappedLineParser::parseIfThenElse() {
176 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
177 nextToken();
178 parseParens();
179 bool NeedsUnwrappedLine = false;
180 if (FormatTok.Tok.is(tok::l_brace)) {
181 parseBlock();
182 NeedsUnwrappedLine = true;
183 } else {
184 addUnwrappedLine();
185 ++Line.Level;
186 parseStatement();
187 --Line.Level;
188 }
189 if (FormatTok.Tok.is(tok::kw_else)) {
190 nextToken();
191 if (FormatTok.Tok.is(tok::l_brace)) {
192 parseBlock();
193 addUnwrappedLine();
194 } else if (FormatTok.Tok.is(tok::kw_if)) {
195 parseIfThenElse();
196 } else {
197 addUnwrappedLine();
198 ++Line.Level;
199 parseStatement();
200 --Line.Level;
201 }
202 } else if (NeedsUnwrappedLine) {
203 addUnwrappedLine();
204 }
205}
206
207void UnwrappedLineParser::parseDoWhile() {
208 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
209 nextToken();
210 if (FormatTok.Tok.is(tok::l_brace)) {
211 parseBlock();
212 } else {
213 addUnwrappedLine();
214 ++Line.Level;
215 parseStatement();
216 --Line.Level;
217 }
218
219 assert(FormatTok.Tok.is(tok::kw_while) && "'while' expected");
220 nextToken();
221 parseStatement();
222}
223
224void UnwrappedLineParser::parseLabel() {
225 // FIXME: remove all asserts.
226 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
227 nextToken();
228 unsigned OldLineLevel = Line.Level;
229 if (Line.Level > 0)
230 --Line.Level;
231 if (FormatTok.Tok.is(tok::l_brace)) {
232 parseBlock();
233 }
234 addUnwrappedLine();
235 Line.Level = OldLineLevel;
236}
237
238void UnwrappedLineParser::parseCaseLabel() {
239 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
240 // FIXME: fix handling of complex expressions here.
241 do {
242 nextToken();
243 } while (!eof() && !FormatTok.Tok.is(tok::colon));
244 parseLabel();
245}
246
247void UnwrappedLineParser::parseSwitch() {
248 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
249 nextToken();
250 parseParens();
251 if (FormatTok.Tok.is(tok::l_brace)) {
252 parseBlock();
253 addUnwrappedLine();
254 } else {
255 addUnwrappedLine();
256 ++Line.Level;
257 parseStatement();
258 --Line.Level;
259 }
260}
261
262void UnwrappedLineParser::parseAccessSpecifier() {
263 nextToken();
264 nextToken();
265 addUnwrappedLine();
266}
267
268void UnwrappedLineParser::parseEnum() {
269 do {
270 nextToken();
271 if (FormatTok.Tok.is(tok::semi)) {
272 nextToken();
273 addUnwrappedLine();
274 return;
275 }
276 } while (!eof());
277}
278
279void UnwrappedLineParser::addUnwrappedLine() {
280 // Consume trailing comments.
281 while (!eof() && FormatTok.NewlinesBefore == 0 &&
282 FormatTok.Tok.is(tok::comment)) {
283 nextToken();
284 }
285 Callback.formatUnwrappedLine(Line);
286 Line.Tokens.clear();
287}
288
289bool UnwrappedLineParser::eof() const {
290 return FormatTok.Tok.is(tok::eof);
291}
292
293void UnwrappedLineParser::nextToken() {
294 if (eof())
295 return;
296 Line.Tokens.push_back(FormatTok);
297 parseToken();
298}
299
300void UnwrappedLineParser::parseToken() {
301 if (GreaterStashed) {
302 FormatTok.NewlinesBefore = 0;
303 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
304 FormatTok.WhiteSpaceLength = 0;
305 GreaterStashed = false;
306 return;
307 }
308
309 FormatTok = FormatToken();
310 Lex.LexFromRawLexer(FormatTok.Tok);
311 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
312
313 // Consume and record whitespace until we find a significant token.
314 while (FormatTok.Tok.is(tok::unknown)) {
315 FormatTok.NewlinesBefore += tokenText().count('\n');
316 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
317
318 if (eof())
319 return;
320 Lex.LexFromRawLexer(FormatTok.Tok);
321 }
322
323 if (FormatTok.Tok.is(tok::raw_identifier)) {
324 const IdentifierInfo &Info = IdentTable.get(tokenText());
325 FormatTok.Tok.setKind(Info.getTokenID());
326 }
327
328 if (FormatTok.Tok.is(tok::greatergreater)) {
329 FormatTok.Tok.setKind(tok::greater);
330 GreaterStashed = true;
331 }
332}
333
334StringRef UnwrappedLineParser::tokenText() {
335 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
336 FormatTok.Tok.getLength());
337 return Data;
338}
339
340} // end namespace format
341} // end namespace clang