blob: 70f33ad0315cadfc1482cb4ad7aea79e26f8f806 [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() {
44 // FIXME: Write test that breaks due to a missing
45 // if (eof()) return createEOF();
46 Token = PreviousTokenSource->getNextToken();
47 if (eof())
48 return createEOF();
49 return Token;
50 }
51
52private:
53 bool eof() {
54 return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline;
55 }
56
57 FormatToken createEOF() {
58 FormatToken FormatTok;
59 FormatTok.Tok.startToken();
60 FormatTok.Tok.setKind(tok::eof);
61 return FormatTok;
62 }
63
64 UnwrappedLine &Line;
65 FormatTokenSource *&TokenSource;
66 FormatToken &ResetToken;
Manuel Klimekc37b4d62013-01-05 22:14:16 +000067 unsigned PreviousLineLevel;
Manuel Klimekd4397b92013-01-04 23:34:14 +000068 FormatTokenSource *PreviousTokenSource;
69
70 FormatToken Token;
71};
72
Alexander Kornienko469a21b2012-12-07 16:15:44 +000073UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
74 FormatTokenSource &Tokens,
Daniel Jasperbac016b2012-12-03 18:12:45 +000075 UnwrappedLineConsumer &Callback)
Manuel Klimekd4397b92013-01-04 23:34:14 +000076 : Style(Style), Tokens(&Tokens), Callback(Callback) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000077}
78
Alexander Kornienkocff563c2012-12-04 17:27:50 +000079bool UnwrappedLineParser::parse() {
Manuel Klimekd4397b92013-01-04 23:34:14 +000080 readToken();
81 return parseFile();
82}
83
84bool UnwrappedLineParser::parseFile() {
Manuel Klimeka5342db2013-01-06 20:07:31 +000085 bool Error = parseLevel(/*HasOpeningBrace=*/false);
Manuel Klimekd4397b92013-01-04 23:34:14 +000086 // Make sure to format the remaining tokens.
87 addUnwrappedLine();
88 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000089}
90
Manuel Klimeka5342db2013-01-06 20:07:31 +000091bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
Alexander Kornienkocff563c2012-12-04 17:27:50 +000092 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000093 do {
94 switch (FormatTok.Tok.getKind()) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000095 case tok::comment:
Daniel Jasper05b1ac82012-12-17 11:29:41 +000096 nextToken();
97 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +000098 break;
99 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000100 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000101 addUnwrappedLine();
102 break;
103 case tok::r_brace:
Manuel Klimeka5342db2013-01-06 20:07:31 +0000104 if (HasOpeningBrace) {
105 return false;
106 } else {
107 // Stray '}' is an error.
108 Error = true;
109 nextToken();
110 addUnwrappedLine();
111 }
112 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000113 default:
114 parseStatement();
115 break;
116 }
117 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000118 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000119}
120
Alexander Kornienko15757312012-12-06 18:03:27 +0000121bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000122 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +0000123 nextToken();
124
Daniel Jasperbac016b2012-12-03 18:12:45 +0000125 addUnwrappedLine();
126
Alexander Kornienko15757312012-12-06 18:03:27 +0000127 Line.Level += AddLevels;
Manuel Klimeka5342db2013-01-06 20:07:31 +0000128 parseLevel(/*HasOpeningBrace=*/true);
Alexander Kornienko15757312012-12-06 18:03:27 +0000129 Line.Level -= AddLevels;
130
Alexander Kornienko393b0082012-12-04 15:40:36 +0000131 // FIXME: Add error handling.
132 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
Daniel Jasperbac016b2012-12-03 18:12:45 +0000135 nextToken();
136 if (FormatTok.Tok.is(tok::semi))
137 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000138 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000139}
140
141void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000142 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
Manuel Klimekd4397b92013-01-04 23:34:14 +0000143 ScopedMacroState MacroState(Line, Tokens, FormatTok);
Manuel Klimeka080a182013-01-02 16:30:12 +0000144 nextToken();
145
Manuel Klimeka080a182013-01-02 16:30:12 +0000146 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
147 addUnwrappedLine();
Manuel Klimeka080a182013-01-02 16:30:12 +0000148 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000149 }
Manuel Klimeka080a182013-01-02 16:30:12 +0000150
Manuel Klimekd4397b92013-01-04 23:34:14 +0000151 switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
152 case tok::pp_define:
153 parsePPDefine();
154 break;
155 default:
156 parsePPUnknown();
157 break;
158 }
159}
160
161void UnwrappedLineParser::parsePPDefine() {
162 nextToken();
163
164 if (FormatTok.Tok.getKind() != tok::identifier) {
165 parsePPUnknown();
166 return;
167 }
168 nextToken();
169 if (FormatTok.Tok.getKind() == tok::l_paren) {
170 parseParens();
171 }
172 addUnwrappedLine();
173 Line.Level = 1;
Manuel Klimekc3d0c822013-01-07 09:34:28 +0000174
175 // Errors during a preprocessor directive can only affect the layout of the
176 // preprocessor directive, and thus we ignore them. An alternative approach
177 // would be to use the same approach we use on the file level (no
178 // re-indentation if there was a structural error) within the macro
179 // definition.
Manuel Klimekd4397b92013-01-04 23:34:14 +0000180 parseFile();
181}
182
183void UnwrappedLineParser::parsePPUnknown() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000184 do {
Manuel Klimeka080a182013-01-02 16:30:12 +0000185 nextToken();
186 } while (!eof());
187 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000188}
189
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000190void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000191 // Consume leading line comments, e.g. for branches without compounds.
192 while (FormatTok.Tok.is(tok::comment)) {
193 nextToken();
194 addUnwrappedLine();
195 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000196}
197
198void UnwrappedLineParser::parseStatement() {
199 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000200
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000201 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000202 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000203 case tok::kw_namespace:
204 parseNamespace();
205 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000206 case tok::kw_inline:
207 nextToken();
208 TokenNumber++;
209 if (FormatTok.Tok.is(tok::kw_namespace)) {
210 parseNamespace();
211 return;
212 }
213 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000214 case tok::kw_public:
215 case tok::kw_protected:
216 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000217 parseAccessSpecifier();
218 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000219 case tok::kw_if:
220 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000221 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000222 case tok::kw_for:
223 case tok::kw_while:
224 parseForOrWhileLoop();
225 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000226 case tok::kw_do:
227 parseDoWhile();
228 return;
229 case tok::kw_switch:
230 parseSwitch();
231 return;
232 case tok::kw_default:
233 nextToken();
234 parseLabel();
235 return;
236 case tok::kw_case:
237 parseCaseLabel();
238 return;
239 default:
240 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000241 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000242 do {
243 ++TokenNumber;
244 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000245 case tok::kw_enum:
246 parseEnum();
247 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000248 case tok::semi:
249 nextToken();
250 addUnwrappedLine();
251 return;
252 case tok::l_paren:
253 parseParens();
254 break;
255 case tok::l_brace:
256 parseBlock();
257 addUnwrappedLine();
258 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000259 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000260 nextToken();
261 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
262 parseLabel();
263 return;
264 }
265 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000266 case tok::equal:
267 nextToken();
268 // Skip initializers as they will be formatted by a later step.
269 if (FormatTok.Tok.is(tok::l_brace))
270 nextToken();
271 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000272 default:
273 nextToken();
274 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000275 }
276 } while (!eof());
277}
278
279void UnwrappedLineParser::parseParens() {
280 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
281 nextToken();
282 do {
283 switch (FormatTok.Tok.getKind()) {
284 case tok::l_paren:
285 parseParens();
286 break;
287 case tok::r_paren:
288 nextToken();
289 return;
290 default:
291 nextToken();
292 break;
293 }
294 } while (!eof());
295}
296
297void UnwrappedLineParser::parseIfThenElse() {
298 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
299 nextToken();
300 parseParens();
301 bool NeedsUnwrappedLine = false;
302 if (FormatTok.Tok.is(tok::l_brace)) {
303 parseBlock();
304 NeedsUnwrappedLine = true;
305 } else {
306 addUnwrappedLine();
307 ++Line.Level;
308 parseStatement();
309 --Line.Level;
310 }
311 if (FormatTok.Tok.is(tok::kw_else)) {
312 nextToken();
313 if (FormatTok.Tok.is(tok::l_brace)) {
314 parseBlock();
315 addUnwrappedLine();
316 } else if (FormatTok.Tok.is(tok::kw_if)) {
317 parseIfThenElse();
318 } else {
319 addUnwrappedLine();
320 ++Line.Level;
321 parseStatement();
322 --Line.Level;
323 }
324 } else if (NeedsUnwrappedLine) {
325 addUnwrappedLine();
326 }
327}
328
Alexander Kornienko15757312012-12-06 18:03:27 +0000329void UnwrappedLineParser::parseNamespace() {
330 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
331 nextToken();
332 if (FormatTok.Tok.is(tok::identifier))
333 nextToken();
334 if (FormatTok.Tok.is(tok::l_brace)) {
335 parseBlock(0);
336 addUnwrappedLine();
337 }
338 // FIXME: Add error handling.
339}
340
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000341void UnwrappedLineParser::parseForOrWhileLoop() {
342 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
343 "'for' or 'while' expected");
344 nextToken();
345 parseParens();
346 if (FormatTok.Tok.is(tok::l_brace)) {
347 parseBlock();
348 addUnwrappedLine();
349 } else {
350 addUnwrappedLine();
351 ++Line.Level;
352 parseStatement();
353 --Line.Level;
354 }
355}
356
Daniel Jasperbac016b2012-12-03 18:12:45 +0000357void UnwrappedLineParser::parseDoWhile() {
358 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
359 nextToken();
360 if (FormatTok.Tok.is(tok::l_brace)) {
361 parseBlock();
362 } else {
363 addUnwrappedLine();
364 ++Line.Level;
365 parseStatement();
366 --Line.Level;
367 }
368
Alexander Kornienko393b0082012-12-04 15:40:36 +0000369 // FIXME: Add error handling.
370 if (!FormatTok.Tok.is(tok::kw_while)) {
371 addUnwrappedLine();
372 return;
373 }
374
Daniel Jasperbac016b2012-12-03 18:12:45 +0000375 nextToken();
376 parseStatement();
377}
378
379void UnwrappedLineParser::parseLabel() {
380 // FIXME: remove all asserts.
381 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
382 nextToken();
383 unsigned OldLineLevel = Line.Level;
384 if (Line.Level > 0)
385 --Line.Level;
386 if (FormatTok.Tok.is(tok::l_brace)) {
387 parseBlock();
388 }
389 addUnwrappedLine();
390 Line.Level = OldLineLevel;
391}
392
393void UnwrappedLineParser::parseCaseLabel() {
394 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
395 // FIXME: fix handling of complex expressions here.
396 do {
397 nextToken();
398 } while (!eof() && !FormatTok.Tok.is(tok::colon));
399 parseLabel();
400}
401
402void UnwrappedLineParser::parseSwitch() {
403 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
404 nextToken();
405 parseParens();
406 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000407 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000408 addUnwrappedLine();
409 } else {
410 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000411 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000412 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000413 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000414 }
415}
416
417void UnwrappedLineParser::parseAccessSpecifier() {
418 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000419 // Otherwise, we don't know what it is, and we'd better keep the next token.
420 if (FormatTok.Tok.is(tok::colon))
421 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000422 addUnwrappedLine();
423}
424
425void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000426 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000427 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000428 switch (FormatTok.Tok.getKind()) {
429 case tok::l_brace:
430 nextToken();
431 addUnwrappedLine();
432 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000433 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000434 break;
435 case tok::l_paren:
436 parseParens();
437 break;
438 case tok::comma:
439 nextToken();
440 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000441 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000442 break;
443 case tok::r_brace:
444 if (HasContents)
445 addUnwrappedLine();
446 --Line.Level;
447 nextToken();
448 break;
449 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000450 nextToken();
451 addUnwrappedLine();
452 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000453 default:
454 HasContents = true;
455 nextToken();
456 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000457 }
458 } while (!eof());
459}
460
461void UnwrappedLineParser::addUnwrappedLine() {
462 // Consume trailing comments.
463 while (!eof() && FormatTok.NewlinesBefore == 0 &&
464 FormatTok.Tok.is(tok::comment)) {
465 nextToken();
466 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000467 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000468 Line.Tokens.clear();
469}
470
471bool UnwrappedLineParser::eof() const {
472 return FormatTok.Tok.is(tok::eof);
473}
474
475void UnwrappedLineParser::nextToken() {
476 if (eof())
477 return;
478 Line.Tokens.push_back(FormatTok);
Manuel Klimekd4397b92013-01-04 23:34:14 +0000479 readToken();
480}
481
482void UnwrappedLineParser::readToken() {
483 FormatTok = Tokens->getNextToken();
Manuel Klimekf6fd00b2013-01-05 22:56:06 +0000484 while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash) &&
485 ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
486 FormatTok.IsFirst)) {
Manuel Klimekd4397b92013-01-04 23:34:14 +0000487 // FIXME: This is incorrect - the correct way is to create a
488 // data structure that will construct the parts around the preprocessor
489 // directive as a structured \c UnwrappedLine.
490 addUnwrappedLine();
491 parsePPDirective();
492 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000493}
494
495} // end namespace format
496} // end namespace clang