blob: 2f3a6034bcff8f029511a38f4edd200e034d9903 [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() {
87 bool Error = parseLevel();
88 // Make sure to format the remaining tokens.
89 addUnwrappedLine();
90 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000091}
92
Alexander Kornienkocff563c2012-12-04 17:27:50 +000093bool UnwrappedLineParser::parseLevel() {
94 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:
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000106 // Stray '}' is an error.
107 return true;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000108 default:
109 parseStatement();
110 break;
111 }
112 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000113 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000114}
115
Alexander Kornienko15757312012-12-06 18:03:27 +0000116bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000117 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +0000118 nextToken();
119
Daniel Jasperbac016b2012-12-03 18:12:45 +0000120 addUnwrappedLine();
121
Alexander Kornienko15757312012-12-06 18:03:27 +0000122 Line.Level += AddLevels;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000123 parseLevel();
Alexander Kornienko15757312012-12-06 18:03:27 +0000124 Line.Level -= AddLevels;
125
Alexander Kornienko393b0082012-12-04 15:40:36 +0000126 // FIXME: Add error handling.
127 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000128 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +0000129
Daniel Jasperbac016b2012-12-03 18:12:45 +0000130 nextToken();
131 if (FormatTok.Tok.is(tok::semi))
132 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000133 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000134}
135
136void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000137 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
Manuel Klimekd4397b92013-01-04 23:34:14 +0000138 ScopedMacroState MacroState(Line, Tokens, FormatTok);
Manuel Klimeka080a182013-01-02 16:30:12 +0000139 nextToken();
140
Manuel Klimeka080a182013-01-02 16:30:12 +0000141 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
142 addUnwrappedLine();
Manuel Klimeka080a182013-01-02 16:30:12 +0000143 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000144 }
Manuel Klimeka080a182013-01-02 16:30:12 +0000145
Manuel Klimekd4397b92013-01-04 23:34:14 +0000146 switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
147 case tok::pp_define:
148 parsePPDefine();
149 break;
150 default:
151 parsePPUnknown();
152 break;
153 }
154}
155
156void UnwrappedLineParser::parsePPDefine() {
157 nextToken();
158
159 if (FormatTok.Tok.getKind() != tok::identifier) {
160 parsePPUnknown();
161 return;
162 }
163 nextToken();
164 if (FormatTok.Tok.getKind() == tok::l_paren) {
165 parseParens();
166 }
167 addUnwrappedLine();
168 Line.Level = 1;
169 parseFile();
170}
171
172void UnwrappedLineParser::parsePPUnknown() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000173 do {
Manuel Klimeka080a182013-01-02 16:30:12 +0000174 nextToken();
175 } while (!eof());
176 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000177}
178
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000179void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000180 // Consume leading line comments, e.g. for branches without compounds.
181 while (FormatTok.Tok.is(tok::comment)) {
182 nextToken();
183 addUnwrappedLine();
184 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000185}
186
187void UnwrappedLineParser::parseStatement() {
188 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000189
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000190 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000191 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000192 case tok::kw_namespace:
193 parseNamespace();
194 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000195 case tok::kw_inline:
196 nextToken();
197 TokenNumber++;
198 if (FormatTok.Tok.is(tok::kw_namespace)) {
199 parseNamespace();
200 return;
201 }
202 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000203 case tok::kw_public:
204 case tok::kw_protected:
205 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000206 parseAccessSpecifier();
207 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000208 case tok::kw_if:
209 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000210 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000211 case tok::kw_for:
212 case tok::kw_while:
213 parseForOrWhileLoop();
214 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000215 case tok::kw_do:
216 parseDoWhile();
217 return;
218 case tok::kw_switch:
219 parseSwitch();
220 return;
221 case tok::kw_default:
222 nextToken();
223 parseLabel();
224 return;
225 case tok::kw_case:
226 parseCaseLabel();
227 return;
228 default:
229 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000230 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000231 do {
232 ++TokenNumber;
233 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000234 case tok::kw_enum:
235 parseEnum();
236 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000237 case tok::semi:
238 nextToken();
239 addUnwrappedLine();
240 return;
241 case tok::l_paren:
242 parseParens();
243 break;
244 case tok::l_brace:
245 parseBlock();
246 addUnwrappedLine();
247 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000248 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000249 nextToken();
250 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
251 parseLabel();
252 return;
253 }
254 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000255 case tok::equal:
256 nextToken();
257 // Skip initializers as they will be formatted by a later step.
258 if (FormatTok.Tok.is(tok::l_brace))
259 nextToken();
260 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000261 default:
262 nextToken();
263 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000264 }
265 } while (!eof());
266}
267
268void UnwrappedLineParser::parseParens() {
269 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
270 nextToken();
271 do {
272 switch (FormatTok.Tok.getKind()) {
273 case tok::l_paren:
274 parseParens();
275 break;
276 case tok::r_paren:
277 nextToken();
278 return;
279 default:
280 nextToken();
281 break;
282 }
283 } while (!eof());
284}
285
286void UnwrappedLineParser::parseIfThenElse() {
287 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
288 nextToken();
289 parseParens();
290 bool NeedsUnwrappedLine = false;
291 if (FormatTok.Tok.is(tok::l_brace)) {
292 parseBlock();
293 NeedsUnwrappedLine = true;
294 } else {
295 addUnwrappedLine();
296 ++Line.Level;
297 parseStatement();
298 --Line.Level;
299 }
300 if (FormatTok.Tok.is(tok::kw_else)) {
301 nextToken();
302 if (FormatTok.Tok.is(tok::l_brace)) {
303 parseBlock();
304 addUnwrappedLine();
305 } else if (FormatTok.Tok.is(tok::kw_if)) {
306 parseIfThenElse();
307 } else {
308 addUnwrappedLine();
309 ++Line.Level;
310 parseStatement();
311 --Line.Level;
312 }
313 } else if (NeedsUnwrappedLine) {
314 addUnwrappedLine();
315 }
316}
317
Alexander Kornienko15757312012-12-06 18:03:27 +0000318void UnwrappedLineParser::parseNamespace() {
319 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
320 nextToken();
321 if (FormatTok.Tok.is(tok::identifier))
322 nextToken();
323 if (FormatTok.Tok.is(tok::l_brace)) {
324 parseBlock(0);
325 addUnwrappedLine();
326 }
327 // FIXME: Add error handling.
328}
329
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000330void UnwrappedLineParser::parseForOrWhileLoop() {
331 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
332 "'for' or 'while' expected");
333 nextToken();
334 parseParens();
335 if (FormatTok.Tok.is(tok::l_brace)) {
336 parseBlock();
337 addUnwrappedLine();
338 } else {
339 addUnwrappedLine();
340 ++Line.Level;
341 parseStatement();
342 --Line.Level;
343 }
344}
345
Daniel Jasperbac016b2012-12-03 18:12:45 +0000346void UnwrappedLineParser::parseDoWhile() {
347 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
348 nextToken();
349 if (FormatTok.Tok.is(tok::l_brace)) {
350 parseBlock();
351 } else {
352 addUnwrappedLine();
353 ++Line.Level;
354 parseStatement();
355 --Line.Level;
356 }
357
Alexander Kornienko393b0082012-12-04 15:40:36 +0000358 // FIXME: Add error handling.
359 if (!FormatTok.Tok.is(tok::kw_while)) {
360 addUnwrappedLine();
361 return;
362 }
363
Daniel Jasperbac016b2012-12-03 18:12:45 +0000364 nextToken();
365 parseStatement();
366}
367
368void UnwrappedLineParser::parseLabel() {
369 // FIXME: remove all asserts.
370 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
371 nextToken();
372 unsigned OldLineLevel = Line.Level;
373 if (Line.Level > 0)
374 --Line.Level;
375 if (FormatTok.Tok.is(tok::l_brace)) {
376 parseBlock();
377 }
378 addUnwrappedLine();
379 Line.Level = OldLineLevel;
380}
381
382void UnwrappedLineParser::parseCaseLabel() {
383 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
384 // FIXME: fix handling of complex expressions here.
385 do {
386 nextToken();
387 } while (!eof() && !FormatTok.Tok.is(tok::colon));
388 parseLabel();
389}
390
391void UnwrappedLineParser::parseSwitch() {
392 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
393 nextToken();
394 parseParens();
395 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000396 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000397 addUnwrappedLine();
398 } else {
399 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000400 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000401 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000402 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000403 }
404}
405
406void UnwrappedLineParser::parseAccessSpecifier() {
407 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000408 // Otherwise, we don't know what it is, and we'd better keep the next token.
409 if (FormatTok.Tok.is(tok::colon))
410 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000411 addUnwrappedLine();
412}
413
414void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000415 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000416 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000417 switch (FormatTok.Tok.getKind()) {
418 case tok::l_brace:
419 nextToken();
420 addUnwrappedLine();
421 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000422 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000423 break;
424 case tok::l_paren:
425 parseParens();
426 break;
427 case tok::comma:
428 nextToken();
429 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000430 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000431 break;
432 case tok::r_brace:
433 if (HasContents)
434 addUnwrappedLine();
435 --Line.Level;
436 nextToken();
437 break;
438 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000439 nextToken();
440 addUnwrappedLine();
441 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000442 default:
443 HasContents = true;
444 nextToken();
445 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000446 }
447 } while (!eof());
448}
449
450void UnwrappedLineParser::addUnwrappedLine() {
451 // Consume trailing comments.
452 while (!eof() && FormatTok.NewlinesBefore == 0 &&
453 FormatTok.Tok.is(tok::comment)) {
454 nextToken();
455 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000456 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000457 Line.Tokens.clear();
458}
459
460bool UnwrappedLineParser::eof() const {
461 return FormatTok.Tok.is(tok::eof);
462}
463
464void UnwrappedLineParser::nextToken() {
465 if (eof())
466 return;
467 Line.Tokens.push_back(FormatTok);
Manuel Klimekd4397b92013-01-04 23:34:14 +0000468 readToken();
469}
470
471void UnwrappedLineParser::readToken() {
472 FormatTok = Tokens->getNextToken();
Manuel Klimek6f8424b2013-01-05 21:34:55 +0000473 while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash)) {
Manuel Klimekd4397b92013-01-04 23:34:14 +0000474 // FIXME: This is incorrect - the correct way is to create a
475 // data structure that will construct the parts around the preprocessor
476 // directive as a structured \c UnwrappedLine.
477 addUnwrappedLine();
478 parsePPDirective();
479 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000480}
481
482} // end namespace format
483} // end namespace clang