blob: 8545f336b86f0efe825831165e789a579590450a [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)
Alexander Kornienko469a21b2012-12-07 16:15:44 +000028 : Style(Style),
29 Tokens(Tokens),
Daniel Jasperbac016b2012-12-03 18:12:45 +000030 Callback(Callback) {
Daniel Jasperbac016b2012-12-03 18:12:45 +000031}
32
Alexander Kornienkocff563c2012-12-04 17:27:50 +000033bool UnwrappedLineParser::parse() {
Alexander Kornienko469a21b2012-12-07 16:15:44 +000034 FormatTok = Tokens.getNextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000035 return parseLevel();
Daniel Jasperbac016b2012-12-03 18:12:45 +000036}
37
Alexander Kornienkocff563c2012-12-04 17:27:50 +000038bool UnwrappedLineParser::parseLevel() {
39 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000040 do {
41 switch (FormatTok.Tok.getKind()) {
42 case tok::hash:
43 parsePPDirective();
44 break;
45 case tok::comment:
46 parseComment();
47 break;
48 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +000049 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +000050 addUnwrappedLine();
51 break;
52 case tok::r_brace:
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000053 // Stray '}' is an error.
54 return true;
Daniel Jasperbac016b2012-12-03 18:12:45 +000055 default:
56 parseStatement();
57 break;
58 }
59 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +000060 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000061}
62
Alexander Kornienko15757312012-12-06 18:03:27 +000063bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000064 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +000065 nextToken();
66
Daniel Jasperbac016b2012-12-03 18:12:45 +000067 addUnwrappedLine();
68
Alexander Kornienko15757312012-12-06 18:03:27 +000069 Line.Level += AddLevels;
Daniel Jasperbac016b2012-12-03 18:12:45 +000070 parseLevel();
Alexander Kornienko15757312012-12-06 18:03:27 +000071 Line.Level -= AddLevels;
72
Alexander Kornienko393b0082012-12-04 15:40:36 +000073 // FIXME: Add error handling.
74 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +000075 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +000076
Daniel Jasperbac016b2012-12-03 18:12:45 +000077 nextToken();
78 if (FormatTok.Tok.is(tok::semi))
79 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000080 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000081}
82
83void UnwrappedLineParser::parsePPDirective() {
84 while (!eof()) {
85 nextToken();
86 if (FormatTok.NewlinesBefore > 0) {
87 addUnwrappedLine();
88 return;
89 }
90 }
91}
92
93void UnwrappedLineParser::parseComment() {
94 while (!eof()) {
95 nextToken();
96 if (FormatTok.NewlinesBefore > 0) {
97 addUnwrappedLine();
98 return;
99 }
100 }
101}
102
103void UnwrappedLineParser::parseStatement() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000104 // Consume leading line comments, e.g. for branches without compounds.
105 while (FormatTok.Tok.is(tok::comment)) {
106 nextToken();
107 addUnwrappedLine();
108 }
109
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000110 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000111 case tok::kw_namespace:
112 parseNamespace();
113 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000114 case tok::kw_public:
115 case tok::kw_protected:
116 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000117 parseAccessSpecifier();
118 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000119 case tok::kw_if:
120 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000121 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000122 case tok::kw_for:
123 case tok::kw_while:
124 parseForOrWhileLoop();
125 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000126 case tok::kw_do:
127 parseDoWhile();
128 return;
129 case tok::kw_switch:
130 parseSwitch();
131 return;
132 case tok::kw_default:
133 nextToken();
134 parseLabel();
135 return;
136 case tok::kw_case:
137 parseCaseLabel();
138 return;
139 default:
140 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000141 }
142 int TokenNumber = 0;
143 do {
144 ++TokenNumber;
145 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000146 case tok::kw_enum:
147 parseEnum();
148 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000149 case tok::semi:
150 nextToken();
151 addUnwrappedLine();
152 return;
153 case tok::l_paren:
154 parseParens();
155 break;
156 case tok::l_brace:
157 parseBlock();
158 addUnwrappedLine();
159 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000160 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000161 nextToken();
162 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
163 parseLabel();
164 return;
165 }
166 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000167 default:
168 nextToken();
169 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000170 }
171 } while (!eof());
172}
173
174void UnwrappedLineParser::parseParens() {
175 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
176 nextToken();
177 do {
178 switch (FormatTok.Tok.getKind()) {
179 case tok::l_paren:
180 parseParens();
181 break;
182 case tok::r_paren:
183 nextToken();
184 return;
185 default:
186 nextToken();
187 break;
188 }
189 } while (!eof());
190}
191
192void UnwrappedLineParser::parseIfThenElse() {
193 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
194 nextToken();
195 parseParens();
196 bool NeedsUnwrappedLine = false;
197 if (FormatTok.Tok.is(tok::l_brace)) {
198 parseBlock();
199 NeedsUnwrappedLine = true;
200 } else {
201 addUnwrappedLine();
202 ++Line.Level;
203 parseStatement();
204 --Line.Level;
205 }
206 if (FormatTok.Tok.is(tok::kw_else)) {
207 nextToken();
208 if (FormatTok.Tok.is(tok::l_brace)) {
209 parseBlock();
210 addUnwrappedLine();
211 } else if (FormatTok.Tok.is(tok::kw_if)) {
212 parseIfThenElse();
213 } else {
214 addUnwrappedLine();
215 ++Line.Level;
216 parseStatement();
217 --Line.Level;
218 }
219 } else if (NeedsUnwrappedLine) {
220 addUnwrappedLine();
221 }
222}
223
Alexander Kornienko15757312012-12-06 18:03:27 +0000224void UnwrappedLineParser::parseNamespace() {
225 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
226 nextToken();
227 if (FormatTok.Tok.is(tok::identifier))
228 nextToken();
229 if (FormatTok.Tok.is(tok::l_brace)) {
230 parseBlock(0);
231 addUnwrappedLine();
232 }
233 // FIXME: Add error handling.
234}
235
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000236void UnwrappedLineParser::parseForOrWhileLoop() {
237 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
238 "'for' or 'while' expected");
239 nextToken();
240 parseParens();
241 if (FormatTok.Tok.is(tok::l_brace)) {
242 parseBlock();
243 addUnwrappedLine();
244 } else {
245 addUnwrappedLine();
246 ++Line.Level;
247 parseStatement();
248 --Line.Level;
249 }
250}
251
Daniel Jasperbac016b2012-12-03 18:12:45 +0000252void UnwrappedLineParser::parseDoWhile() {
253 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
254 nextToken();
255 if (FormatTok.Tok.is(tok::l_brace)) {
256 parseBlock();
257 } else {
258 addUnwrappedLine();
259 ++Line.Level;
260 parseStatement();
261 --Line.Level;
262 }
263
Alexander Kornienko393b0082012-12-04 15:40:36 +0000264 // FIXME: Add error handling.
265 if (!FormatTok.Tok.is(tok::kw_while)) {
266 addUnwrappedLine();
267 return;
268 }
269
Daniel Jasperbac016b2012-12-03 18:12:45 +0000270 nextToken();
271 parseStatement();
272}
273
274void UnwrappedLineParser::parseLabel() {
275 // FIXME: remove all asserts.
276 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
277 nextToken();
278 unsigned OldLineLevel = Line.Level;
279 if (Line.Level > 0)
280 --Line.Level;
281 if (FormatTok.Tok.is(tok::l_brace)) {
282 parseBlock();
283 }
284 addUnwrappedLine();
285 Line.Level = OldLineLevel;
286}
287
288void UnwrappedLineParser::parseCaseLabel() {
289 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
290 // FIXME: fix handling of complex expressions here.
291 do {
292 nextToken();
293 } while (!eof() && !FormatTok.Tok.is(tok::colon));
294 parseLabel();
295}
296
297void UnwrappedLineParser::parseSwitch() {
298 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
299 nextToken();
300 parseParens();
301 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000302 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000303 addUnwrappedLine();
304 } else {
305 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000306 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000307 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000308 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000309 }
310}
311
312void UnwrappedLineParser::parseAccessSpecifier() {
313 nextToken();
Alexander Kornienko56e49c52012-12-10 16:34:48 +0000314 // Otherwise, we don't know what it is, and we'd better keep the next token.
315 if (FormatTok.Tok.is(tok::colon))
316 nextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000317 addUnwrappedLine();
318}
319
320void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000321 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000322 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000323 switch (FormatTok.Tok.getKind()) {
324 case tok::l_brace:
325 nextToken();
326 addUnwrappedLine();
327 ++Line.Level;
328 break;
329 case tok::l_paren:
330 parseParens();
331 break;
332 case tok::comma:
333 nextToken();
334 addUnwrappedLine();
335 break;
336 case tok::r_brace:
337 if (HasContents)
338 addUnwrappedLine();
339 --Line.Level;
340 nextToken();
341 break;
342 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000343 nextToken();
344 addUnwrappedLine();
345 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000346 default:
347 HasContents = true;
348 nextToken();
349 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000350 }
351 } while (!eof());
352}
353
354void UnwrappedLineParser::addUnwrappedLine() {
355 // Consume trailing comments.
356 while (!eof() && FormatTok.NewlinesBefore == 0 &&
357 FormatTok.Tok.is(tok::comment)) {
358 nextToken();
359 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000360 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000361 Line.Tokens.clear();
362}
363
364bool UnwrappedLineParser::eof() const {
365 return FormatTok.Tok.is(tok::eof);
366}
367
368void UnwrappedLineParser::nextToken() {
369 if (eof())
370 return;
371 Line.Tokens.push_back(FormatTok);
Alexander Kornienko469a21b2012-12-07 16:15:44 +0000372 FormatTok = Tokens.getNextToken();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000373}
374
375} // end namespace format
376} // end namespace clang