blob: 4066b55ecb78f4bf96caede37c99070df8d5e80c [file] [log] [blame]
Daniel Jasperbac016b2012-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"
Daniel Jasperbac016b2012-12-03 18:12:45 +000020#include "llvm/Support/raw_ostream.h"
21
22namespace clang {
23namespace format {
24
Manuel Klimekd4397b92013-01-04 23:34:14 +000025class ScopedMacroState : public FormatTokenSource {
26public:
27 ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
28 FormatToken &ResetToken)
29 : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
Manuel Klimekc37b4d62013-01-05 22:14:16 +000030 PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource) {
Manuel Klimekd4397b92013-01-04 23:34:14 +000031 TokenSource = this;
Manuel Klimekc37b4d62013-01-05 22:14:16 +000032 Line.Level = 0;
Manuel Klimekd4397b92013-01-04 23:34:14 +000033 Line.InPPDirective = true;
34 }
35
36 ~ScopedMacroState() {
37 TokenSource = PreviousTokenSource;
38 ResetToken = Token;
39 Line.InPPDirective = false;
Manuel Klimekc37b4d62013-01-05 22:14:16 +000040 Line.Level = PreviousLineLevel;
Manuel Klimekd4397b92013-01-04 23:34:14 +000041 }
42
43 virtual FormatToken getNextToken() {
Manuel Klimekdd5b1012013-01-07 10:03:37 +000044 // The \c UnwrappedLineParser guards against this by never calling
45 // \c getNextToken() after it has encountered the first eof token.
46 assert(!eof());
Manuel Klimekd4397b92013-01-04 23:34:14 +000047 Token = PreviousTokenSource->getNextToken();
48 if (eof())
49 return createEOF();
50 return Token;
51 }
52
53private:
54 bool eof() {
55 return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline;
56 }
57
58 FormatToken createEOF() {
59 FormatToken FormatTok;
60 FormatTok.Tok.startToken();
61 FormatTok.Tok.setKind(tok::eof);
62 return FormatTok;
63 }
64
65 UnwrappedLine &Line;
66 FormatTokenSource *&TokenSource;
67 FormatToken &ResetToken;
Manuel Klimekc37b4d62013-01-05 22:14:16 +000068 unsigned PreviousLineLevel;
Manuel Klimekd4397b92013-01-04 23:34:14 +000069 FormatTokenSource *PreviousTokenSource;
70
71 FormatToken Token;
72};
73
Alexander Kornienko469a21b2012-12-07 16:15:44 +000074UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
75 FormatTokenSource &Tokens,
Daniel Jasperbac016b2012-12-03 18:12:45 +000076 UnwrappedLineConsumer &Callback)
Manuel Klimekd4397b92013-01-04 23:34:14 +000077 : Style(Style), Tokens(&Tokens), Callback(Callback) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000078}
79
Alexander Kornienkocff563c2012-12-04 17:27:50 +000080bool UnwrappedLineParser::parse() {
Manuel Klimekd4397b92013-01-04 23:34:14 +000081 readToken();
82 return parseFile();
83}
84
85bool UnwrappedLineParser::parseFile() {
Manuel Klimeka5342db2013-01-06 20:07:31 +000086 bool Error = parseLevel(/*HasOpeningBrace=*/false);
Manuel Klimekd4397b92013-01-04 23:34:14 +000087 // Make sure to format the remaining tokens.
88 addUnwrappedLine();
89 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000090}
91
Manuel Klimeka5342db2013-01-06 20:07:31 +000092bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
Alexander Kornienkocff563c2012-12-04 17:27:50 +000093 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000094 do {
95 switch (FormatTok.Tok.getKind()) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000096 case tok::comment:
Daniel Jasper05b1ac82012-12-17 11:29:41 +000097 nextToken();
98 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +000099 break;
100 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000101 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000102 addUnwrappedLine();
103 break;
104 case tok::r_brace:
Manuel Klimeka5342db2013-01-06 20:07:31 +0000105 if (HasOpeningBrace) {
106 return false;
107 } else {
108 // Stray '}' is an error.
109 Error = true;
110 nextToken();
111 addUnwrappedLine();
112 }
113 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000114 default:
115 parseStatement();
116 break;
117 }
118 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000119 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000120}
121
Alexander Kornienko15757312012-12-06 18:03:27 +0000122bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000123 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +0000124 nextToken();
125
Daniel Jasperbac016b2012-12-03 18:12:45 +0000126 addUnwrappedLine();
127
Alexander Kornienko15757312012-12-06 18:03:27 +0000128 Line.Level += AddLevels;
Manuel Klimeka5342db2013-01-06 20:07:31 +0000129 parseLevel(/*HasOpeningBrace=*/true);
Alexander Kornienko15757312012-12-06 18:03:27 +0000130 Line.Level -= AddLevels;
131
Alexander Kornienko393b0082012-12-04 15:40:36 +0000132 // FIXME: Add error handling.
133 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000134 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +0000135
Daniel Jasperbac016b2012-12-03 18:12:45 +0000136 nextToken();
137 if (FormatTok.Tok.is(tok::semi))
138 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000139 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000140}
141
142void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000143 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
Manuel Klimekd4397b92013-01-04 23:34:14 +0000144 ScopedMacroState MacroState(Line, Tokens, FormatTok);
Manuel Klimeka080a182013-01-02 16:30:12 +0000145 nextToken();
146
Manuel Klimeka080a182013-01-02 16:30:12 +0000147 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
148 addUnwrappedLine();
Manuel Klimeka080a182013-01-02 16:30:12 +0000149 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000150 }
Manuel Klimeka080a182013-01-02 16:30:12 +0000151
Manuel Klimekd4397b92013-01-04 23:34:14 +0000152 switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
153 case tok::pp_define:
154 parsePPDefine();
155 break;
156 default:
157 parsePPUnknown();
158 break;
159 }
160}
161
162void UnwrappedLineParser::parsePPDefine() {
163 nextToken();
164
165 if (FormatTok.Tok.getKind() != tok::identifier) {
166 parsePPUnknown();
167 return;
168 }
169 nextToken();
170 if (FormatTok.Tok.getKind() == tok::l_paren) {
171 parseParens();
172 }
173 addUnwrappedLine();
174 Line.Level = 1;
Manuel Klimekc3d0c822013-01-07 09:34:28 +0000175
176 // Errors during a preprocessor directive can only affect the layout of the
177 // preprocessor directive, and thus we ignore them. An alternative approach
178 // would be to use the same approach we use on the file level (no
179 // re-indentation if there was a structural error) within the macro
180 // definition.
Manuel Klimekd4397b92013-01-04 23:34:14 +0000181 parseFile();
182}
183
184void UnwrappedLineParser::parsePPUnknown() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000185 do {
Manuel Klimeka080a182013-01-02 16:30:12 +0000186 nextToken();
187 } while (!eof());
188 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000189}
190
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000191void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000192 // Consume leading line comments, e.g. for branches without compounds.
193 while (FormatTok.Tok.is(tok::comment)) {
194 nextToken();
195 addUnwrappedLine();
196 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000197}
198
199void UnwrappedLineParser::parseStatement() {
200 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000201
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000202 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000203 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000204 case tok::kw_namespace:
205 parseNamespace();
206 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000207 case tok::kw_inline:
208 nextToken();
209 TokenNumber++;
210 if (FormatTok.Tok.is(tok::kw_namespace)) {
211 parseNamespace();
212 return;
213 }
214 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000215 case tok::kw_public:
216 case tok::kw_protected:
217 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000218 parseAccessSpecifier();
219 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000220 case tok::kw_if:
221 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000222 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000223 case tok::kw_for:
224 case tok::kw_while:
225 parseForOrWhileLoop();
226 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000227 case tok::kw_do:
228 parseDoWhile();
229 return;
230 case tok::kw_switch:
231 parseSwitch();
232 return;
233 case tok::kw_default:
234 nextToken();
235 parseLabel();
236 return;
237 case tok::kw_case:
238 parseCaseLabel();
239 return;
240 default:
241 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000242 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000243 do {
244 ++TokenNumber;
245 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000246 case tok::kw_enum:
247 parseEnum();
248 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000249 case tok::semi:
250 nextToken();
251 addUnwrappedLine();
252 return;
253 case tok::l_paren:
254 parseParens();
255 break;
256 case tok::l_brace:
257 parseBlock();
258 addUnwrappedLine();
259 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000260 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000261 nextToken();
262 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
263 parseLabel();
264 return;
265 }
266 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000267 case tok::equal:
268 nextToken();
269 // Skip initializers as they will be formatted by a later step.
270 if (FormatTok.Tok.is(tok::l_brace))
271 nextToken();
272 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000273 default:
274 nextToken();
275 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000276 }
277 } while (!eof());
278}
279
280void UnwrappedLineParser::parseParens() {
281 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
282 nextToken();
283 do {
284 switch (FormatTok.Tok.getKind()) {
285 case tok::l_paren:
286 parseParens();
287 break;
288 case tok::r_paren:
289 nextToken();
290 return;
291 default:
292 nextToken();
293 break;
294 }
295 } while (!eof());
296}
297
298void UnwrappedLineParser::parseIfThenElse() {
299 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
300 nextToken();
301 parseParens();
302 bool NeedsUnwrappedLine = false;
303 if (FormatTok.Tok.is(tok::l_brace)) {
304 parseBlock();
305 NeedsUnwrappedLine = true;
306 } else {
307 addUnwrappedLine();
308 ++Line.Level;
309 parseStatement();
310 --Line.Level;
311 }
312 if (FormatTok.Tok.is(tok::kw_else)) {
313 nextToken();
314 if (FormatTok.Tok.is(tok::l_brace)) {
315 parseBlock();
316 addUnwrappedLine();
317 } else if (FormatTok.Tok.is(tok::kw_if)) {
318 parseIfThenElse();
319 } else {
320 addUnwrappedLine();
321 ++Line.Level;
322 parseStatement();
323 --Line.Level;
324 }
325 } else if (NeedsUnwrappedLine) {
326 addUnwrappedLine();
327 }
328}
329
Alexander Kornienko15757312012-12-06 18:03:27 +0000330void UnwrappedLineParser::parseNamespace() {
331 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
332 nextToken();
333 if (FormatTok.Tok.is(tok::identifier))
334 nextToken();
335 if (FormatTok.Tok.is(tok::l_brace)) {
336 parseBlock(0);
337 addUnwrappedLine();
338 }
339 // FIXME: Add error handling.
340}
341
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000342void UnwrappedLineParser::parseForOrWhileLoop() {
343 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
344 "'for' or 'while' expected");
345 nextToken();
346 parseParens();
347 if (FormatTok.Tok.is(tok::l_brace)) {
348 parseBlock();
349 addUnwrappedLine();
350 } else {
351 addUnwrappedLine();
352 ++Line.Level;
353 parseStatement();
354 --Line.Level;
355 }
356}
357
Daniel Jasperbac016b2012-12-03 18:12:45 +0000358void UnwrappedLineParser::parseDoWhile() {
359 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
360 nextToken();
361 if (FormatTok.Tok.is(tok::l_brace)) {
362 parseBlock();
363 } else {
364 addUnwrappedLine();
365 ++Line.Level;
366 parseStatement();
367 --Line.Level;
368 }
369
Alexander Kornienko393b0082012-12-04 15:40:36 +0000370 // FIXME: Add error handling.
371 if (!FormatTok.Tok.is(tok::kw_while)) {
372 addUnwrappedLine();
373 return;
374 }
375
Daniel Jasperbac016b2012-12-03 18:12:45 +0000376 nextToken();
377 parseStatement();
378}
379
380void UnwrappedLineParser::parseLabel() {
381 // FIXME: remove all asserts.
382 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
383 nextToken();
384 unsigned OldLineLevel = Line.Level;
385 if (Line.Level > 0)
386 --Line.Level;
387 if (FormatTok.Tok.is(tok::l_brace)) {
388 parseBlock();
389 }
390 addUnwrappedLine();
391 Line.Level = OldLineLevel;
392}
393
394void UnwrappedLineParser::parseCaseLabel() {
395 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
396 // FIXME: fix handling of complex expressions here.
397 do {
398 nextToken();
399 } while (!eof() && !FormatTok.Tok.is(tok::colon));
400 parseLabel();
401}
402
403void UnwrappedLineParser::parseSwitch() {
404 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
405 nextToken();
406 parseParens();
407 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000408 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000409 addUnwrappedLine();
410 } else {
411 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000412 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000413 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000414 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000415 }
416}
417
418void UnwrappedLineParser::parseAccessSpecifier() {
419 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000420 // Otherwise, we don't know what it is, and we'd better keep the next token.
421 if (FormatTok.Tok.is(tok::colon))
422 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000423 addUnwrappedLine();
424}
425
426void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000427 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000428 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000429 switch (FormatTok.Tok.getKind()) {
430 case tok::l_brace:
431 nextToken();
432 addUnwrappedLine();
433 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000434 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000435 break;
436 case tok::l_paren:
437 parseParens();
438 break;
439 case tok::comma:
440 nextToken();
441 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000442 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000443 break;
444 case tok::r_brace:
445 if (HasContents)
446 addUnwrappedLine();
447 --Line.Level;
448 nextToken();
449 break;
450 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000451 nextToken();
452 addUnwrappedLine();
453 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000454 default:
455 HasContents = true;
456 nextToken();
457 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000458 }
459 } while (!eof());
460}
461
462void UnwrappedLineParser::addUnwrappedLine() {
463 // Consume trailing comments.
464 while (!eof() && FormatTok.NewlinesBefore == 0 &&
465 FormatTok.Tok.is(tok::comment)) {
466 nextToken();
467 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000468 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000469 Line.Tokens.clear();
470}
471
472bool UnwrappedLineParser::eof() const {
473 return FormatTok.Tok.is(tok::eof);
474}
475
476void UnwrappedLineParser::nextToken() {
477 if (eof())
478 return;
479 Line.Tokens.push_back(FormatTok);
Manuel Klimekd4397b92013-01-04 23:34:14 +0000480 readToken();
481}
482
483void UnwrappedLineParser::readToken() {
484 FormatTok = Tokens->getNextToken();
Manuel Klimekf6fd00b2013-01-05 22:56:06 +0000485 while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash) &&
486 ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
487 FormatTok.IsFirst)) {
Manuel Klimekd4397b92013-01-04 23:34:14 +0000488 // FIXME: This is incorrect - the correct way is to create a
489 // data structure that will construct the parts around the preprocessor
490 // directive as a structured \c UnwrappedLine.
491 addUnwrappedLine();
492 parsePPDirective();
493 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000494}
495
496} // end namespace format
497} // end namespace clang