blob: 00710827c2a11e02659fac477ca061950ceb175f [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;
32 // FIXME: Back up all other state (errors, line indent, etc) and reset after
33 // parsing the macro.
Manuel Klimekc37b4d62013-01-05 22:14:16 +000034 Line.Level = 0;
Manuel Klimekd4397b92013-01-04 23:34:14 +000035 Line.InPPDirective = true;
36 }
37
38 ~ScopedMacroState() {
39 TokenSource = PreviousTokenSource;
40 ResetToken = Token;
41 Line.InPPDirective = false;
Manuel Klimekc37b4d62013-01-05 22:14:16 +000042 Line.Level = PreviousLineLevel;
Manuel Klimekd4397b92013-01-04 23:34:14 +000043 }
44
45 virtual FormatToken getNextToken() {
46 // FIXME: Write test that breaks due to a missing
47 // if (eof()) return createEOF();
48 Token = PreviousTokenSource->getNextToken();
49 if (eof())
50 return createEOF();
51 return Token;
52 }
53
54private:
55 bool eof() {
56 return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline;
57 }
58
59 FormatToken createEOF() {
60 FormatToken FormatTok;
61 FormatTok.Tok.startToken();
62 FormatTok.Tok.setKind(tok::eof);
63 return FormatTok;
64 }
65
66 UnwrappedLine &Line;
67 FormatTokenSource *&TokenSource;
68 FormatToken &ResetToken;
Manuel Klimekc37b4d62013-01-05 22:14:16 +000069 unsigned PreviousLineLevel;
Manuel Klimekd4397b92013-01-04 23:34:14 +000070 FormatTokenSource *PreviousTokenSource;
71
72 FormatToken Token;
73};
74
Alexander Kornienko469a21b2012-12-07 16:15:44 +000075UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
76 FormatTokenSource &Tokens,
Daniel Jasperbac016b2012-12-03 18:12:45 +000077 UnwrappedLineConsumer &Callback)
Manuel Klimekd4397b92013-01-04 23:34:14 +000078 : Style(Style), Tokens(&Tokens), Callback(Callback) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000079}
80
Alexander Kornienkocff563c2012-12-04 17:27:50 +000081bool UnwrappedLineParser::parse() {
Manuel Klimekd4397b92013-01-04 23:34:14 +000082 readToken();
83 return parseFile();
84}
85
86bool UnwrappedLineParser::parseFile() {
Manuel Klimeka5342db2013-01-06 20:07:31 +000087 bool Error = parseLevel(/*HasOpeningBrace=*/false);
Manuel Klimekd4397b92013-01-04 23:34:14 +000088 // Make sure to format the remaining tokens.
89 addUnwrappedLine();
90 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000091}
92
Manuel Klimeka5342db2013-01-06 20:07:31 +000093bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
Alexander Kornienkocff563c2012-12-04 17:27:50 +000094 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000095 do {
96 switch (FormatTok.Tok.getKind()) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000097 case tok::comment:
Daniel Jasper05b1ac82012-12-17 11:29:41 +000098 nextToken();
99 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000100 break;
101 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000102 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000103 addUnwrappedLine();
104 break;
105 case tok::r_brace:
Manuel Klimeka5342db2013-01-06 20:07:31 +0000106 if (HasOpeningBrace) {
107 return false;
108 } else {
109 // Stray '}' is an error.
110 Error = true;
111 nextToken();
112 addUnwrappedLine();
113 }
114 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000115 default:
116 parseStatement();
117 break;
118 }
119 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000120 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000121}
122
Alexander Kornienko15757312012-12-06 18:03:27 +0000123bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000124 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +0000125 nextToken();
126
Daniel Jasperbac016b2012-12-03 18:12:45 +0000127 addUnwrappedLine();
128
Alexander Kornienko15757312012-12-06 18:03:27 +0000129 Line.Level += AddLevels;
Manuel Klimeka5342db2013-01-06 20:07:31 +0000130 parseLevel(/*HasOpeningBrace=*/true);
Alexander Kornienko15757312012-12-06 18:03:27 +0000131 Line.Level -= AddLevels;
132
Alexander Kornienko393b0082012-12-04 15:40:36 +0000133 // FIXME: Add error handling.
134 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000135 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +0000136
Daniel Jasperbac016b2012-12-03 18:12:45 +0000137 nextToken();
138 if (FormatTok.Tok.is(tok::semi))
139 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000140 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000141}
142
143void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000144 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
Manuel Klimekd4397b92013-01-04 23:34:14 +0000145 ScopedMacroState MacroState(Line, Tokens, FormatTok);
Manuel Klimeka080a182013-01-02 16:30:12 +0000146 nextToken();
147
Manuel Klimeka080a182013-01-02 16:30:12 +0000148 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
149 addUnwrappedLine();
Manuel Klimeka080a182013-01-02 16:30:12 +0000150 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000151 }
Manuel Klimeka080a182013-01-02 16:30:12 +0000152
Manuel Klimekd4397b92013-01-04 23:34:14 +0000153 switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
154 case tok::pp_define:
155 parsePPDefine();
156 break;
157 default:
158 parsePPUnknown();
159 break;
160 }
161}
162
163void UnwrappedLineParser::parsePPDefine() {
164 nextToken();
165
166 if (FormatTok.Tok.getKind() != tok::identifier) {
167 parsePPUnknown();
168 return;
169 }
170 nextToken();
171 if (FormatTok.Tok.getKind() == tok::l_paren) {
172 parseParens();
173 }
174 addUnwrappedLine();
175 Line.Level = 1;
176 parseFile();
177}
178
179void UnwrappedLineParser::parsePPUnknown() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000180 do {
Manuel Klimeka080a182013-01-02 16:30:12 +0000181 nextToken();
182 } while (!eof());
183 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000184}
185
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000186void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000187 // Consume leading line comments, e.g. for branches without compounds.
188 while (FormatTok.Tok.is(tok::comment)) {
189 nextToken();
190 addUnwrappedLine();
191 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000192}
193
194void UnwrappedLineParser::parseStatement() {
195 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000196
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000197 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000198 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000199 case tok::kw_namespace:
200 parseNamespace();
201 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000202 case tok::kw_inline:
203 nextToken();
204 TokenNumber++;
205 if (FormatTok.Tok.is(tok::kw_namespace)) {
206 parseNamespace();
207 return;
208 }
209 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000210 case tok::kw_public:
211 case tok::kw_protected:
212 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000213 parseAccessSpecifier();
214 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000215 case tok::kw_if:
216 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000217 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000218 case tok::kw_for:
219 case tok::kw_while:
220 parseForOrWhileLoop();
221 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000222 case tok::kw_do:
223 parseDoWhile();
224 return;
225 case tok::kw_switch:
226 parseSwitch();
227 return;
228 case tok::kw_default:
229 nextToken();
230 parseLabel();
231 return;
232 case tok::kw_case:
233 parseCaseLabel();
234 return;
235 default:
236 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000237 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000238 do {
239 ++TokenNumber;
240 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000241 case tok::kw_enum:
242 parseEnum();
243 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000244 case tok::semi:
245 nextToken();
246 addUnwrappedLine();
247 return;
248 case tok::l_paren:
249 parseParens();
250 break;
251 case tok::l_brace:
252 parseBlock();
253 addUnwrappedLine();
254 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000255 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000256 nextToken();
257 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
258 parseLabel();
259 return;
260 }
261 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000262 case tok::equal:
263 nextToken();
264 // Skip initializers as they will be formatted by a later step.
265 if (FormatTok.Tok.is(tok::l_brace))
266 nextToken();
267 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000268 default:
269 nextToken();
270 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000271 }
272 } while (!eof());
273}
274
275void UnwrappedLineParser::parseParens() {
276 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
277 nextToken();
278 do {
279 switch (FormatTok.Tok.getKind()) {
280 case tok::l_paren:
281 parseParens();
282 break;
283 case tok::r_paren:
284 nextToken();
285 return;
286 default:
287 nextToken();
288 break;
289 }
290 } while (!eof());
291}
292
293void UnwrappedLineParser::parseIfThenElse() {
294 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
295 nextToken();
296 parseParens();
297 bool NeedsUnwrappedLine = false;
298 if (FormatTok.Tok.is(tok::l_brace)) {
299 parseBlock();
300 NeedsUnwrappedLine = true;
301 } else {
302 addUnwrappedLine();
303 ++Line.Level;
304 parseStatement();
305 --Line.Level;
306 }
307 if (FormatTok.Tok.is(tok::kw_else)) {
308 nextToken();
309 if (FormatTok.Tok.is(tok::l_brace)) {
310 parseBlock();
311 addUnwrappedLine();
312 } else if (FormatTok.Tok.is(tok::kw_if)) {
313 parseIfThenElse();
314 } else {
315 addUnwrappedLine();
316 ++Line.Level;
317 parseStatement();
318 --Line.Level;
319 }
320 } else if (NeedsUnwrappedLine) {
321 addUnwrappedLine();
322 }
323}
324
Alexander Kornienko15757312012-12-06 18:03:27 +0000325void UnwrappedLineParser::parseNamespace() {
326 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
327 nextToken();
328 if (FormatTok.Tok.is(tok::identifier))
329 nextToken();
330 if (FormatTok.Tok.is(tok::l_brace)) {
331 parseBlock(0);
332 addUnwrappedLine();
333 }
334 // FIXME: Add error handling.
335}
336
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000337void UnwrappedLineParser::parseForOrWhileLoop() {
338 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
339 "'for' or 'while' expected");
340 nextToken();
341 parseParens();
342 if (FormatTok.Tok.is(tok::l_brace)) {
343 parseBlock();
344 addUnwrappedLine();
345 } else {
346 addUnwrappedLine();
347 ++Line.Level;
348 parseStatement();
349 --Line.Level;
350 }
351}
352
Daniel Jasperbac016b2012-12-03 18:12:45 +0000353void UnwrappedLineParser::parseDoWhile() {
354 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
355 nextToken();
356 if (FormatTok.Tok.is(tok::l_brace)) {
357 parseBlock();
358 } else {
359 addUnwrappedLine();
360 ++Line.Level;
361 parseStatement();
362 --Line.Level;
363 }
364
Alexander Kornienko393b0082012-12-04 15:40:36 +0000365 // FIXME: Add error handling.
366 if (!FormatTok.Tok.is(tok::kw_while)) {
367 addUnwrappedLine();
368 return;
369 }
370
Daniel Jasperbac016b2012-12-03 18:12:45 +0000371 nextToken();
372 parseStatement();
373}
374
375void UnwrappedLineParser::parseLabel() {
376 // FIXME: remove all asserts.
377 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
378 nextToken();
379 unsigned OldLineLevel = Line.Level;
380 if (Line.Level > 0)
381 --Line.Level;
382 if (FormatTok.Tok.is(tok::l_brace)) {
383 parseBlock();
384 }
385 addUnwrappedLine();
386 Line.Level = OldLineLevel;
387}
388
389void UnwrappedLineParser::parseCaseLabel() {
390 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
391 // FIXME: fix handling of complex expressions here.
392 do {
393 nextToken();
394 } while (!eof() && !FormatTok.Tok.is(tok::colon));
395 parseLabel();
396}
397
398void UnwrappedLineParser::parseSwitch() {
399 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
400 nextToken();
401 parseParens();
402 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000403 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000404 addUnwrappedLine();
405 } else {
406 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000407 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000408 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000409 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000410 }
411}
412
413void UnwrappedLineParser::parseAccessSpecifier() {
414 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000415 // Otherwise, we don't know what it is, and we'd better keep the next token.
416 if (FormatTok.Tok.is(tok::colon))
417 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000418 addUnwrappedLine();
419}
420
421void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000422 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000423 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000424 switch (FormatTok.Tok.getKind()) {
425 case tok::l_brace:
426 nextToken();
427 addUnwrappedLine();
428 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000429 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000430 break;
431 case tok::l_paren:
432 parseParens();
433 break;
434 case tok::comma:
435 nextToken();
436 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000437 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000438 break;
439 case tok::r_brace:
440 if (HasContents)
441 addUnwrappedLine();
442 --Line.Level;
443 nextToken();
444 break;
445 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000446 nextToken();
447 addUnwrappedLine();
448 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000449 default:
450 HasContents = true;
451 nextToken();
452 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000453 }
454 } while (!eof());
455}
456
457void UnwrappedLineParser::addUnwrappedLine() {
458 // Consume trailing comments.
459 while (!eof() && FormatTok.NewlinesBefore == 0 &&
460 FormatTok.Tok.is(tok::comment)) {
461 nextToken();
462 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000463 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000464 Line.Tokens.clear();
465}
466
467bool UnwrappedLineParser::eof() const {
468 return FormatTok.Tok.is(tok::eof);
469}
470
471void UnwrappedLineParser::nextToken() {
472 if (eof())
473 return;
474 Line.Tokens.push_back(FormatTok);
Manuel Klimekd4397b92013-01-04 23:34:14 +0000475 readToken();
476}
477
478void UnwrappedLineParser::readToken() {
479 FormatTok = Tokens->getNextToken();
Manuel Klimekf6fd00b2013-01-05 22:56:06 +0000480 while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash) &&
481 ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
482 FormatTok.IsFirst)) {
Manuel Klimekd4397b92013-01-04 23:34:14 +0000483 // FIXME: This is incorrect - the correct way is to create a
484 // data structure that will construct the parts around the preprocessor
485 // directive as a structured \c UnwrappedLine.
486 addUnwrappedLine();
487 parsePPDirective();
488 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000489}
490
491} // end namespace format
492} // end namespace clang