blob: adb536324a3c6a2f134042b5eb33da9f8e9b4226 [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:
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000115 parseStructuralElement();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000116 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 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000133 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +0000134
Manuel Klimekde768542013-01-07 18:10:23 +0000135 nextToken(); // Munch the closing brace.
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000136 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000137}
138
139void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000140 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
Manuel Klimekd4397b92013-01-04 23:34:14 +0000141 ScopedMacroState MacroState(Line, Tokens, FormatTok);
Manuel Klimeka080a182013-01-02 16:30:12 +0000142 nextToken();
143
Manuel Klimeka080a182013-01-02 16:30:12 +0000144 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
145 addUnwrappedLine();
Manuel Klimeka080a182013-01-02 16:30:12 +0000146 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000147 }
Manuel Klimeka080a182013-01-02 16:30:12 +0000148
Manuel Klimekd4397b92013-01-04 23:34:14 +0000149 switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
150 case tok::pp_define:
151 parsePPDefine();
152 break;
153 default:
154 parsePPUnknown();
155 break;
156 }
157}
158
159void UnwrappedLineParser::parsePPDefine() {
160 nextToken();
161
162 if (FormatTok.Tok.getKind() != tok::identifier) {
163 parsePPUnknown();
164 return;
165 }
166 nextToken();
167 if (FormatTok.Tok.getKind() == tok::l_paren) {
168 parseParens();
169 }
170 addUnwrappedLine();
171 Line.Level = 1;
Manuel Klimekc3d0c822013-01-07 09:34:28 +0000172
173 // Errors during a preprocessor directive can only affect the layout of the
174 // preprocessor directive, and thus we ignore them. An alternative approach
175 // would be to use the same approach we use on the file level (no
176 // re-indentation if there was a structural error) within the macro
177 // definition.
Manuel Klimekd4397b92013-01-04 23:34:14 +0000178 parseFile();
179}
180
181void UnwrappedLineParser::parsePPUnknown() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000182 do {
Manuel Klimeka080a182013-01-02 16:30:12 +0000183 nextToken();
184 } while (!eof());
185 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000186}
187
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000188void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000189 // Consume leading line comments, e.g. for branches without compounds.
190 while (FormatTok.Tok.is(tok::comment)) {
191 nextToken();
192 addUnwrappedLine();
193 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000194}
195
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000196void UnwrappedLineParser::parseStructuralElement() {
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000197 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000198
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000199 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000200 switch (FormatTok.Tok.getKind()) {
Nico Weber6092d4e2013-01-07 19:05:19 +0000201 case tok::at:
202 nextToken();
203 switch (FormatTok.Tok.getObjCKeywordID()) {
204 case tok::objc_public:
205 case tok::objc_protected:
206 case tok::objc_package:
207 case tok::objc_private:
208 return parseAccessSpecifier();
209 default:
210 break;
211 }
212 break;
Alexander Kornienko15757312012-12-06 18:03:27 +0000213 case tok::kw_namespace:
214 parseNamespace();
215 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000216 case tok::kw_inline:
217 nextToken();
218 TokenNumber++;
219 if (FormatTok.Tok.is(tok::kw_namespace)) {
220 parseNamespace();
221 return;
222 }
223 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000224 case tok::kw_public:
225 case tok::kw_protected:
226 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000227 parseAccessSpecifier();
228 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000229 case tok::kw_if:
230 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000231 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000232 case tok::kw_for:
233 case tok::kw_while:
234 parseForOrWhileLoop();
235 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000236 case tok::kw_do:
237 parseDoWhile();
238 return;
239 case tok::kw_switch:
240 parseSwitch();
241 return;
242 case tok::kw_default:
243 nextToken();
244 parseLabel();
245 return;
246 case tok::kw_case:
247 parseCaseLabel();
248 return;
249 default:
250 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000251 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000252 do {
253 ++TokenNumber;
254 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000255 case tok::kw_enum:
256 parseEnum();
257 return;
Manuel Klimekde768542013-01-07 18:10:23 +0000258 case tok::kw_struct: // fallthrough
259 case tok::kw_class:
260 parseStructOrClass();
261 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000262 case tok::semi:
263 nextToken();
264 addUnwrappedLine();
265 return;
266 case tok::l_paren:
267 parseParens();
268 break;
269 case tok::l_brace:
270 parseBlock();
271 addUnwrappedLine();
272 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000273 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000274 nextToken();
275 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
276 parseLabel();
277 return;
278 }
279 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000280 case tok::equal:
281 nextToken();
282 // Skip initializers as they will be formatted by a later step.
283 if (FormatTok.Tok.is(tok::l_brace))
284 nextToken();
285 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000286 default:
287 nextToken();
288 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000289 }
290 } while (!eof());
291}
292
293void UnwrappedLineParser::parseParens() {
294 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
295 nextToken();
296 do {
297 switch (FormatTok.Tok.getKind()) {
298 case tok::l_paren:
299 parseParens();
300 break;
301 case tok::r_paren:
302 nextToken();
303 return;
304 default:
305 nextToken();
306 break;
307 }
308 } while (!eof());
309}
310
311void UnwrappedLineParser::parseIfThenElse() {
312 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
313 nextToken();
314 parseParens();
315 bool NeedsUnwrappedLine = false;
316 if (FormatTok.Tok.is(tok::l_brace)) {
317 parseBlock();
318 NeedsUnwrappedLine = true;
319 } else {
320 addUnwrappedLine();
321 ++Line.Level;
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000322 parseStructuralElement();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000323 --Line.Level;
324 }
325 if (FormatTok.Tok.is(tok::kw_else)) {
326 nextToken();
327 if (FormatTok.Tok.is(tok::l_brace)) {
328 parseBlock();
329 addUnwrappedLine();
330 } else if (FormatTok.Tok.is(tok::kw_if)) {
331 parseIfThenElse();
332 } else {
333 addUnwrappedLine();
334 ++Line.Level;
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000335 parseStructuralElement();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000336 --Line.Level;
337 }
338 } else if (NeedsUnwrappedLine) {
339 addUnwrappedLine();
340 }
341}
342
Alexander Kornienko15757312012-12-06 18:03:27 +0000343void UnwrappedLineParser::parseNamespace() {
344 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
345 nextToken();
346 if (FormatTok.Tok.is(tok::identifier))
347 nextToken();
348 if (FormatTok.Tok.is(tok::l_brace)) {
349 parseBlock(0);
350 addUnwrappedLine();
351 }
352 // FIXME: Add error handling.
353}
354
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000355void UnwrappedLineParser::parseForOrWhileLoop() {
356 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
357 "'for' or 'while' expected");
358 nextToken();
359 parseParens();
360 if (FormatTok.Tok.is(tok::l_brace)) {
361 parseBlock();
362 addUnwrappedLine();
363 } else {
364 addUnwrappedLine();
365 ++Line.Level;
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000366 parseStructuralElement();
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000367 --Line.Level;
368 }
369}
370
Daniel Jasperbac016b2012-12-03 18:12:45 +0000371void UnwrappedLineParser::parseDoWhile() {
372 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
373 nextToken();
374 if (FormatTok.Tok.is(tok::l_brace)) {
375 parseBlock();
376 } else {
377 addUnwrappedLine();
378 ++Line.Level;
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000379 parseStructuralElement();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000380 --Line.Level;
381 }
382
Alexander Kornienko393b0082012-12-04 15:40:36 +0000383 // FIXME: Add error handling.
384 if (!FormatTok.Tok.is(tok::kw_while)) {
385 addUnwrappedLine();
386 return;
387 }
388
Daniel Jasperbac016b2012-12-03 18:12:45 +0000389 nextToken();
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000390 parseStructuralElement();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000391}
392
393void UnwrappedLineParser::parseLabel() {
394 // FIXME: remove all asserts.
395 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
396 nextToken();
397 unsigned OldLineLevel = Line.Level;
398 if (Line.Level > 0)
399 --Line.Level;
400 if (FormatTok.Tok.is(tok::l_brace)) {
401 parseBlock();
402 }
403 addUnwrappedLine();
404 Line.Level = OldLineLevel;
405}
406
407void UnwrappedLineParser::parseCaseLabel() {
408 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
409 // FIXME: fix handling of complex expressions here.
410 do {
411 nextToken();
412 } while (!eof() && !FormatTok.Tok.is(tok::colon));
413 parseLabel();
414}
415
416void UnwrappedLineParser::parseSwitch() {
417 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
418 nextToken();
419 parseParens();
420 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000421 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000422 addUnwrappedLine();
423 } else {
424 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000425 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Manuel Klimekf0ab0a32013-01-07 14:56:16 +0000426 parseStructuralElement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000427 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000428 }
429}
430
431void UnwrappedLineParser::parseAccessSpecifier() {
432 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000433 // Otherwise, we don't know what it is, and we'd better keep the next token.
434 if (FormatTok.Tok.is(tok::colon))
435 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000436 addUnwrappedLine();
437}
438
439void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000440 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000441 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000442 switch (FormatTok.Tok.getKind()) {
443 case tok::l_brace:
444 nextToken();
445 addUnwrappedLine();
446 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000447 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000448 break;
449 case tok::l_paren:
450 parseParens();
451 break;
452 case tok::comma:
453 nextToken();
454 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000455 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000456 break;
457 case tok::r_brace:
458 if (HasContents)
459 addUnwrappedLine();
460 --Line.Level;
461 nextToken();
462 break;
463 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000464 nextToken();
465 addUnwrappedLine();
466 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000467 default:
468 HasContents = true;
469 nextToken();
470 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000471 }
472 } while (!eof());
473}
474
Manuel Klimekde768542013-01-07 18:10:23 +0000475void UnwrappedLineParser::parseStructOrClass() {
476 nextToken();
477 do {
478 switch (FormatTok.Tok.getKind()) {
479 case tok::l_brace:
480 // FIXME: Think about how to resolve the error handling here.
481 parseBlock();
482 parseStructuralElement();
483 return;
484 case tok::semi:
485 nextToken();
486 addUnwrappedLine();
487 return;
488 default:
489 nextToken();
490 break;
491 }
492 } while (!eof());
493}
494
Daniel Jasperbac016b2012-12-03 18:12:45 +0000495void UnwrappedLineParser::addUnwrappedLine() {
496 // Consume trailing comments.
497 while (!eof() && FormatTok.NewlinesBefore == 0 &&
498 FormatTok.Tok.is(tok::comment)) {
499 nextToken();
500 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000501 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000502 Line.Tokens.clear();
503}
504
505bool UnwrappedLineParser::eof() const {
506 return FormatTok.Tok.is(tok::eof);
507}
508
509void UnwrappedLineParser::nextToken() {
510 if (eof())
511 return;
512 Line.Tokens.push_back(FormatTok);
Manuel Klimekd4397b92013-01-04 23:34:14 +0000513 readToken();
514}
515
516void UnwrappedLineParser::readToken() {
517 FormatTok = Tokens->getNextToken();
Manuel Klimekf6fd00b2013-01-05 22:56:06 +0000518 while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash) &&
519 ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
520 FormatTok.IsFirst)) {
Manuel Klimekd4397b92013-01-04 23:34:14 +0000521 // FIXME: This is incorrect - the correct way is to create a
522 // data structure that will construct the parts around the preprocessor
523 // directive as a structured \c UnwrappedLine.
524 addUnwrappedLine();
525 parsePPDirective();
526 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000527}
528
Daniel Jaspercd162382013-01-07 13:26:07 +0000529} // end namespace format
530} // end namespace clang