blob: c1bafa9a3b1bb1e6e6df699654affc71e341a884 [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),
30 PreviousTokenSource(TokenSource) {
31 TokenSource = this;
32 // FIXME: Back up all other state (errors, line indent, etc) and reset after
33 // parsing the macro.
34 Line.InPPDirective = true;
35 }
36
37 ~ScopedMacroState() {
38 TokenSource = PreviousTokenSource;
39 ResetToken = Token;
40 Line.InPPDirective = false;
41 Line.Level = 0; // FIXME: Test + this is obviously incorrect
42 }
43
44 virtual FormatToken getNextToken() {
45 // FIXME: Write test that breaks due to a missing
46 // if (eof()) return createEOF();
47 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;
68
69 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() {
86 bool Error = parseLevel();
87 // Make sure to format the remaining tokens.
88 addUnwrappedLine();
89 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000090}
91
Alexander Kornienkocff563c2012-12-04 17:27:50 +000092bool UnwrappedLineParser::parseLevel() {
93 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:
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000105 // Stray '}' is an error.
106 return true;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000107 default:
108 parseStatement();
109 break;
110 }
111 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000112 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000113}
114
Alexander Kornienko15757312012-12-06 18:03:27 +0000115bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +0000116 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +0000117 nextToken();
118
Daniel Jasperbac016b2012-12-03 18:12:45 +0000119 addUnwrappedLine();
120
Alexander Kornienko15757312012-12-06 18:03:27 +0000121 Line.Level += AddLevels;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000122 parseLevel();
Alexander Kornienko15757312012-12-06 18:03:27 +0000123 Line.Level -= AddLevels;
124
Alexander Kornienko393b0082012-12-04 15:40:36 +0000125 // FIXME: Add error handling.
126 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000127 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +0000128
Daniel Jasperbac016b2012-12-03 18:12:45 +0000129 nextToken();
130 if (FormatTok.Tok.is(tok::semi))
131 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +0000132 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000133}
134
135void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000136 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
Manuel Klimekd4397b92013-01-04 23:34:14 +0000137 ScopedMacroState MacroState(Line, Tokens, FormatTok);
Manuel Klimeka080a182013-01-02 16:30:12 +0000138 nextToken();
139
Manuel Klimeka080a182013-01-02 16:30:12 +0000140 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
141 addUnwrappedLine();
Manuel Klimeka080a182013-01-02 16:30:12 +0000142 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000143 }
Manuel Klimeka080a182013-01-02 16:30:12 +0000144
Manuel Klimekd4397b92013-01-04 23:34:14 +0000145 switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
146 case tok::pp_define:
147 parsePPDefine();
148 break;
149 default:
150 parsePPUnknown();
151 break;
152 }
153}
154
155void UnwrappedLineParser::parsePPDefine() {
156 nextToken();
157
158 if (FormatTok.Tok.getKind() != tok::identifier) {
159 parsePPUnknown();
160 return;
161 }
162 nextToken();
163 if (FormatTok.Tok.getKind() == tok::l_paren) {
164 parseParens();
165 }
166 addUnwrappedLine();
167 Line.Level = 1;
168 parseFile();
169}
170
171void UnwrappedLineParser::parsePPUnknown() {
Manuel Klimeka080a182013-01-02 16:30:12 +0000172 do {
Manuel Klimeka080a182013-01-02 16:30:12 +0000173 nextToken();
174 } while (!eof());
175 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000176}
177
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000178void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000179 // Consume leading line comments, e.g. for branches without compounds.
180 while (FormatTok.Tok.is(tok::comment)) {
181 nextToken();
182 addUnwrappedLine();
183 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000184}
185
186void UnwrappedLineParser::parseStatement() {
187 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000188
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000189 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000190 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000191 case tok::kw_namespace:
192 parseNamespace();
193 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000194 case tok::kw_inline:
195 nextToken();
196 TokenNumber++;
197 if (FormatTok.Tok.is(tok::kw_namespace)) {
198 parseNamespace();
199 return;
200 }
201 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000202 case tok::kw_public:
203 case tok::kw_protected:
204 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000205 parseAccessSpecifier();
206 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000207 case tok::kw_if:
208 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000209 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000210 case tok::kw_for:
211 case tok::kw_while:
212 parseForOrWhileLoop();
213 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000214 case tok::kw_do:
215 parseDoWhile();
216 return;
217 case tok::kw_switch:
218 parseSwitch();
219 return;
220 case tok::kw_default:
221 nextToken();
222 parseLabel();
223 return;
224 case tok::kw_case:
225 parseCaseLabel();
226 return;
227 default:
228 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000229 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000230 do {
231 ++TokenNumber;
232 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000233 case tok::kw_enum:
234 parseEnum();
235 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000236 case tok::semi:
237 nextToken();
238 addUnwrappedLine();
239 return;
240 case tok::l_paren:
241 parseParens();
242 break;
243 case tok::l_brace:
244 parseBlock();
245 addUnwrappedLine();
246 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000247 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000248 nextToken();
249 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
250 parseLabel();
251 return;
252 }
253 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000254 case tok::equal:
255 nextToken();
256 // Skip initializers as they will be formatted by a later step.
257 if (FormatTok.Tok.is(tok::l_brace))
258 nextToken();
259 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000260 default:
261 nextToken();
262 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000263 }
264 } while (!eof());
265}
266
267void UnwrappedLineParser::parseParens() {
268 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
269 nextToken();
270 do {
271 switch (FormatTok.Tok.getKind()) {
272 case tok::l_paren:
273 parseParens();
274 break;
275 case tok::r_paren:
276 nextToken();
277 return;
278 default:
279 nextToken();
280 break;
281 }
282 } while (!eof());
283}
284
285void UnwrappedLineParser::parseIfThenElse() {
286 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
287 nextToken();
288 parseParens();
289 bool NeedsUnwrappedLine = false;
290 if (FormatTok.Tok.is(tok::l_brace)) {
291 parseBlock();
292 NeedsUnwrappedLine = true;
293 } else {
294 addUnwrappedLine();
295 ++Line.Level;
296 parseStatement();
297 --Line.Level;
298 }
299 if (FormatTok.Tok.is(tok::kw_else)) {
300 nextToken();
301 if (FormatTok.Tok.is(tok::l_brace)) {
302 parseBlock();
303 addUnwrappedLine();
304 } else if (FormatTok.Tok.is(tok::kw_if)) {
305 parseIfThenElse();
306 } else {
307 addUnwrappedLine();
308 ++Line.Level;
309 parseStatement();
310 --Line.Level;
311 }
312 } else if (NeedsUnwrappedLine) {
313 addUnwrappedLine();
314 }
315}
316
Alexander Kornienko15757312012-12-06 18:03:27 +0000317void UnwrappedLineParser::parseNamespace() {
318 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
319 nextToken();
320 if (FormatTok.Tok.is(tok::identifier))
321 nextToken();
322 if (FormatTok.Tok.is(tok::l_brace)) {
323 parseBlock(0);
324 addUnwrappedLine();
325 }
326 // FIXME: Add error handling.
327}
328
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000329void UnwrappedLineParser::parseForOrWhileLoop() {
330 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
331 "'for' or 'while' expected");
332 nextToken();
333 parseParens();
334 if (FormatTok.Tok.is(tok::l_brace)) {
335 parseBlock();
336 addUnwrappedLine();
337 } else {
338 addUnwrappedLine();
339 ++Line.Level;
340 parseStatement();
341 --Line.Level;
342 }
343}
344
Daniel Jasperbac016b2012-12-03 18:12:45 +0000345void UnwrappedLineParser::parseDoWhile() {
346 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
347 nextToken();
348 if (FormatTok.Tok.is(tok::l_brace)) {
349 parseBlock();
350 } else {
351 addUnwrappedLine();
352 ++Line.Level;
353 parseStatement();
354 --Line.Level;
355 }
356
Alexander Kornienko393b0082012-12-04 15:40:36 +0000357 // FIXME: Add error handling.
358 if (!FormatTok.Tok.is(tok::kw_while)) {
359 addUnwrappedLine();
360 return;
361 }
362
Daniel Jasperbac016b2012-12-03 18:12:45 +0000363 nextToken();
364 parseStatement();
365}
366
367void UnwrappedLineParser::parseLabel() {
368 // FIXME: remove all asserts.
369 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
370 nextToken();
371 unsigned OldLineLevel = Line.Level;
372 if (Line.Level > 0)
373 --Line.Level;
374 if (FormatTok.Tok.is(tok::l_brace)) {
375 parseBlock();
376 }
377 addUnwrappedLine();
378 Line.Level = OldLineLevel;
379}
380
381void UnwrappedLineParser::parseCaseLabel() {
382 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
383 // FIXME: fix handling of complex expressions here.
384 do {
385 nextToken();
386 } while (!eof() && !FormatTok.Tok.is(tok::colon));
387 parseLabel();
388}
389
390void UnwrappedLineParser::parseSwitch() {
391 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
392 nextToken();
393 parseParens();
394 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000395 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000396 addUnwrappedLine();
397 } else {
398 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000399 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000400 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000401 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000402 }
403}
404
405void UnwrappedLineParser::parseAccessSpecifier() {
406 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000407 // Otherwise, we don't know what it is, and we'd better keep the next token.
408 if (FormatTok.Tok.is(tok::colon))
409 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000410 addUnwrappedLine();
411}
412
413void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000414 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000415 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000416 switch (FormatTok.Tok.getKind()) {
417 case tok::l_brace:
418 nextToken();
419 addUnwrappedLine();
420 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000421 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000422 break;
423 case tok::l_paren:
424 parseParens();
425 break;
426 case tok::comma:
427 nextToken();
428 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000429 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000430 break;
431 case tok::r_brace:
432 if (HasContents)
433 addUnwrappedLine();
434 --Line.Level;
435 nextToken();
436 break;
437 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000438 nextToken();
439 addUnwrappedLine();
440 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000441 default:
442 HasContents = true;
443 nextToken();
444 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000445 }
446 } while (!eof());
447}
448
449void UnwrappedLineParser::addUnwrappedLine() {
450 // Consume trailing comments.
451 while (!eof() && FormatTok.NewlinesBefore == 0 &&
452 FormatTok.Tok.is(tok::comment)) {
453 nextToken();
454 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000455 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000456 Line.Tokens.clear();
457}
458
459bool UnwrappedLineParser::eof() const {
460 return FormatTok.Tok.is(tok::eof);
461}
462
463void UnwrappedLineParser::nextToken() {
464 if (eof())
465 return;
466 Line.Tokens.push_back(FormatTok);
Manuel Klimekd4397b92013-01-04 23:34:14 +0000467 readToken();
468}
469
470void UnwrappedLineParser::readToken() {
471 FormatTok = Tokens->getNextToken();
Manuel Klimek6f8424b2013-01-05 21:34:55 +0000472 while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash)) {
Manuel Klimekd4397b92013-01-04 23:34:14 +0000473 // FIXME: This is incorrect - the correct way is to create a
474 // data structure that will construct the parts around the preprocessor
475 // directive as a structured \c UnwrappedLine.
476 addUnwrappedLine();
477 parsePPDirective();
478 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000479}
480
481} // end namespace format
482} // end namespace clang