blob: 614125b9437c6d5231e65f62c23752668571f526 [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
Alexander Kornienko469a21b2012-12-07 16:15:44 +000025UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
26 FormatTokenSource &Tokens,
Daniel Jasperbac016b2012-12-03 18:12:45 +000027 UnwrappedLineConsumer &Callback)
Daniel Jasperd7610b82012-12-24 16:51:15 +000028 : Style(Style), Tokens(Tokens), Callback(Callback) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000029}
30
Alexander Kornienkocff563c2012-12-04 17:27:50 +000031bool UnwrappedLineParser::parse() {
Alexander Kornienko469a21b2012-12-07 16:15:44 +000032 FormatTok = Tokens.getNextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000033 return parseLevel();
Daniel Jasperbac016b2012-12-03 18:12:45 +000034}
35
Alexander Kornienkocff563c2012-12-04 17:27:50 +000036bool UnwrappedLineParser::parseLevel() {
37 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000038 do {
39 switch (FormatTok.Tok.getKind()) {
40 case tok::hash:
41 parsePPDirective();
42 break;
43 case tok::comment:
Daniel Jasper05b1ac82012-12-17 11:29:41 +000044 nextToken();
45 addUnwrappedLine();
Daniel Jasperbac016b2012-12-03 18:12:45 +000046 break;
47 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +000048 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +000049 addUnwrappedLine();
50 break;
51 case tok::r_brace:
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000052 // Stray '}' is an error.
53 return true;
Daniel Jasperbac016b2012-12-03 18:12:45 +000054 default:
55 parseStatement();
56 break;
57 }
58 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +000059 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000060}
61
Alexander Kornienko15757312012-12-06 18:03:27 +000062bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000063 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +000064 nextToken();
65
Daniel Jasperbac016b2012-12-03 18:12:45 +000066 addUnwrappedLine();
67
Alexander Kornienko15757312012-12-06 18:03:27 +000068 Line.Level += AddLevels;
Daniel Jasperbac016b2012-12-03 18:12:45 +000069 parseLevel();
Alexander Kornienko15757312012-12-06 18:03:27 +000070 Line.Level -= AddLevels;
71
Alexander Kornienko393b0082012-12-04 15:40:36 +000072 // FIXME: Add error handling.
73 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +000074 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +000075
Daniel Jasperbac016b2012-12-03 18:12:45 +000076 nextToken();
77 if (FormatTok.Tok.is(tok::semi))
78 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000079 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000080}
81
82void UnwrappedLineParser::parsePPDirective() {
Manuel Klimeka080a182013-01-02 16:30:12 +000083 assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
84 nextToken();
85
86 Line.InPPDirective = true;
87 if (FormatTok.Tok.getIdentifierInfo() == NULL) {
88 addUnwrappedLine();
89 Line.InPPDirective = false;
90 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +000091 }
Manuel Klimeka080a182013-01-02 16:30:12 +000092
93 do {
94 if (FormatTok.NewlinesBefore > 0 &&
95 FormatTok.HasUnescapedNewline) {
96 break;
97 }
98 nextToken();
99 } while (!eof());
100 addUnwrappedLine();
101 Line.InPPDirective = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000102}
103
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000104void UnwrappedLineParser::parseComments() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000105 // Consume leading line comments, e.g. for branches without compounds.
106 while (FormatTok.Tok.is(tok::comment)) {
107 nextToken();
108 addUnwrappedLine();
109 }
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000110}
111
112void UnwrappedLineParser::parseStatement() {
113 parseComments();
Daniel Jasper33182dd2012-12-05 14:57:28 +0000114
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000115 int TokenNumber = 0;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000116 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000117 case tok::kw_namespace:
118 parseNamespace();
119 return;
Dmitri Gribenko1f94f2b2012-12-30 21:27:25 +0000120 case tok::kw_inline:
121 nextToken();
122 TokenNumber++;
123 if (FormatTok.Tok.is(tok::kw_namespace)) {
124 parseNamespace();
125 return;
126 }
127 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000128 case tok::kw_public:
129 case tok::kw_protected:
130 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000131 parseAccessSpecifier();
132 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000133 case tok::kw_if:
134 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000135 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000136 case tok::kw_for:
137 case tok::kw_while:
138 parseForOrWhileLoop();
139 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000140 case tok::kw_do:
141 parseDoWhile();
142 return;
143 case tok::kw_switch:
144 parseSwitch();
145 return;
146 case tok::kw_default:
147 nextToken();
148 parseLabel();
149 return;
150 case tok::kw_case:
151 parseCaseLabel();
152 return;
153 default:
154 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000155 }
Daniel Jasperbac016b2012-12-03 18:12:45 +0000156 do {
157 ++TokenNumber;
158 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000159 case tok::kw_enum:
160 parseEnum();
161 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000162 case tok::semi:
163 nextToken();
164 addUnwrappedLine();
165 return;
166 case tok::l_paren:
167 parseParens();
168 break;
169 case tok::l_brace:
170 parseBlock();
171 addUnwrappedLine();
172 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000173 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000174 nextToken();
175 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
176 parseLabel();
177 return;
178 }
179 break;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000180 case tok::equal:
181 nextToken();
182 // Skip initializers as they will be formatted by a later step.
183 if (FormatTok.Tok.is(tok::l_brace))
184 nextToken();
185 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000186 default:
187 nextToken();
188 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000189 }
190 } while (!eof());
191}
192
193void UnwrappedLineParser::parseParens() {
194 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
195 nextToken();
196 do {
197 switch (FormatTok.Tok.getKind()) {
198 case tok::l_paren:
199 parseParens();
200 break;
201 case tok::r_paren:
202 nextToken();
203 return;
204 default:
205 nextToken();
206 break;
207 }
208 } while (!eof());
209}
210
211void UnwrappedLineParser::parseIfThenElse() {
212 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
213 nextToken();
214 parseParens();
215 bool NeedsUnwrappedLine = false;
216 if (FormatTok.Tok.is(tok::l_brace)) {
217 parseBlock();
218 NeedsUnwrappedLine = true;
219 } else {
220 addUnwrappedLine();
221 ++Line.Level;
222 parseStatement();
223 --Line.Level;
224 }
225 if (FormatTok.Tok.is(tok::kw_else)) {
226 nextToken();
227 if (FormatTok.Tok.is(tok::l_brace)) {
228 parseBlock();
229 addUnwrappedLine();
230 } else if (FormatTok.Tok.is(tok::kw_if)) {
231 parseIfThenElse();
232 } else {
233 addUnwrappedLine();
234 ++Line.Level;
235 parseStatement();
236 --Line.Level;
237 }
238 } else if (NeedsUnwrappedLine) {
239 addUnwrappedLine();
240 }
241}
242
Alexander Kornienko15757312012-12-06 18:03:27 +0000243void UnwrappedLineParser::parseNamespace() {
244 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
245 nextToken();
246 if (FormatTok.Tok.is(tok::identifier))
247 nextToken();
248 if (FormatTok.Tok.is(tok::l_brace)) {
249 parseBlock(0);
250 addUnwrappedLine();
251 }
252 // FIXME: Add error handling.
253}
254
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000255void UnwrappedLineParser::parseForOrWhileLoop() {
256 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
257 "'for' or 'while' expected");
258 nextToken();
259 parseParens();
260 if (FormatTok.Tok.is(tok::l_brace)) {
261 parseBlock();
262 addUnwrappedLine();
263 } else {
264 addUnwrappedLine();
265 ++Line.Level;
266 parseStatement();
267 --Line.Level;
268 }
269}
270
Daniel Jasperbac016b2012-12-03 18:12:45 +0000271void UnwrappedLineParser::parseDoWhile() {
272 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
273 nextToken();
274 if (FormatTok.Tok.is(tok::l_brace)) {
275 parseBlock();
276 } else {
277 addUnwrappedLine();
278 ++Line.Level;
279 parseStatement();
280 --Line.Level;
281 }
282
Alexander Kornienko393b0082012-12-04 15:40:36 +0000283 // FIXME: Add error handling.
284 if (!FormatTok.Tok.is(tok::kw_while)) {
285 addUnwrappedLine();
286 return;
287 }
288
Daniel Jasperbac016b2012-12-03 18:12:45 +0000289 nextToken();
290 parseStatement();
291}
292
293void UnwrappedLineParser::parseLabel() {
294 // FIXME: remove all asserts.
295 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
296 nextToken();
297 unsigned OldLineLevel = Line.Level;
298 if (Line.Level > 0)
299 --Line.Level;
300 if (FormatTok.Tok.is(tok::l_brace)) {
301 parseBlock();
302 }
303 addUnwrappedLine();
304 Line.Level = OldLineLevel;
305}
306
307void UnwrappedLineParser::parseCaseLabel() {
308 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
309 // FIXME: fix handling of complex expressions here.
310 do {
311 nextToken();
312 } while (!eof() && !FormatTok.Tok.is(tok::colon));
313 parseLabel();
314}
315
316void UnwrappedLineParser::parseSwitch() {
317 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
318 nextToken();
319 parseParens();
320 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000321 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000322 addUnwrappedLine();
323 } else {
324 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000325 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000326 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000327 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000328 }
329}
330
331void UnwrappedLineParser::parseAccessSpecifier() {
332 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000333 // Otherwise, we don't know what it is, and we'd better keep the next token.
334 if (FormatTok.Tok.is(tok::colon))
335 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000336 addUnwrappedLine();
337}
338
339void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000340 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000341 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000342 switch (FormatTok.Tok.getKind()) {
343 case tok::l_brace:
344 nextToken();
345 addUnwrappedLine();
346 ++Line.Level;
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000347 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000348 break;
349 case tok::l_paren:
350 parseParens();
351 break;
352 case tok::comma:
353 nextToken();
354 addUnwrappedLine();
Daniel Jasper05b1ac82012-12-17 11:29:41 +0000355 parseComments();
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000356 break;
357 case tok::r_brace:
358 if (HasContents)
359 addUnwrappedLine();
360 --Line.Level;
361 nextToken();
362 break;
363 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000364 nextToken();
365 addUnwrappedLine();
366 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000367 default:
368 HasContents = true;
369 nextToken();
370 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000371 }
372 } while (!eof());
373}
374
375void UnwrappedLineParser::addUnwrappedLine() {
376 // Consume trailing comments.
377 while (!eof() && FormatTok.NewlinesBefore == 0 &&
378 FormatTok.Tok.is(tok::comment)) {
379 nextToken();
380 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000381 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000382 Line.Tokens.clear();
383}
384
385bool UnwrappedLineParser::eof() const {
386 return FormatTok.Tok.is(tok::eof);
387}
388
389void UnwrappedLineParser::nextToken() {
390 if (eof())
391 return;
392 Line.Tokens.push_back(FormatTok);
Alexander Kornienko469a21b2012-12-07 16:15:44 +0000393 FormatTok = Tokens.getNextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000394}
395
396} // end namespace format
397} // end namespace clang