blob: 99e58321cd7fb50a42024c21343fb5795e69ac0d [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
25UnwrappedLineParser::UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr,
26 UnwrappedLineConsumer &Callback)
27 : GreaterStashed(false),
28 Lex(Lex),
29 SourceMgr(SourceMgr),
30 IdentTable(Lex.getLangOpts()),
31 Callback(Callback) {
32 Lex.SetKeepWhitespaceMode(true);
33}
34
Alexander Kornienkocff563c2012-12-04 17:27:50 +000035bool UnwrappedLineParser::parse() {
Daniel Jasperbac016b2012-12-03 18:12:45 +000036 parseToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000037 return parseLevel();
Daniel Jasperbac016b2012-12-03 18:12:45 +000038}
39
Alexander Kornienkocff563c2012-12-04 17:27:50 +000040bool UnwrappedLineParser::parseLevel() {
41 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000042 do {
43 switch (FormatTok.Tok.getKind()) {
44 case tok::hash:
45 parsePPDirective();
46 break;
47 case tok::comment:
48 parseComment();
49 break;
50 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +000051 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +000052 addUnwrappedLine();
53 break;
54 case tok::r_brace:
Alexander Kornienko720ffb62012-12-05 13:56:52 +000055 // FIXME: We need a test when it has to be "return Error;"
Alexander Kornienkocff563c2012-12-04 17:27:50 +000056 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000057 default:
58 parseStatement();
59 break;
60 }
61 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +000062 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000063}
64
Alexander Kornienkocff563c2012-12-04 17:27:50 +000065bool UnwrappedLineParser::parseBlock() {
Daniel Jasperbac016b2012-12-03 18:12:45 +000066 nextToken();
67
68 // FIXME: Remove this hack to handle namespaces.
69 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
70
71 addUnwrappedLine();
72
73 if (!IsNamespace)
74 ++Line.Level;
75 parseLevel();
76 if (!IsNamespace)
77 --Line.Level;
Alexander Kornienko393b0082012-12-04 15:40:36 +000078 // FIXME: Add error handling.
79 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +000080 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +000081
Daniel Jasperbac016b2012-12-03 18:12:45 +000082 nextToken();
83 if (FormatTok.Tok.is(tok::semi))
84 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000085 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000086}
87
88void UnwrappedLineParser::parsePPDirective() {
89 while (!eof()) {
90 nextToken();
91 if (FormatTok.NewlinesBefore > 0) {
92 addUnwrappedLine();
93 return;
94 }
95 }
96}
97
98void UnwrappedLineParser::parseComment() {
99 while (!eof()) {
100 nextToken();
101 if (FormatTok.NewlinesBefore > 0) {
102 addUnwrappedLine();
103 return;
104 }
105 }
106}
107
108void UnwrappedLineParser::parseStatement() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000109 // Consume leading line comments, e.g. for branches without compounds.
110 while (FormatTok.Tok.is(tok::comment)) {
111 nextToken();
112 addUnwrappedLine();
113 }
114
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000115 switch (FormatTok.Tok.getKind()) {
116 case tok::kw_public:
117 case tok::kw_protected:
118 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000119 parseAccessSpecifier();
120 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000121 case tok::kw_if:
122 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000123 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000124 case tok::kw_for:
125 case tok::kw_while:
126 parseForOrWhileLoop();
127 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000128 case tok::kw_do:
129 parseDoWhile();
130 return;
131 case tok::kw_switch:
132 parseSwitch();
133 return;
134 case tok::kw_default:
135 nextToken();
136 parseLabel();
137 return;
138 case tok::kw_case:
139 parseCaseLabel();
140 return;
141 default:
142 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000143 }
144 int TokenNumber = 0;
145 do {
146 ++TokenNumber;
147 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000148 case tok::kw_enum:
149 parseEnum();
150 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000151 case tok::semi:
152 nextToken();
153 addUnwrappedLine();
154 return;
155 case tok::l_paren:
156 parseParens();
157 break;
158 case tok::l_brace:
159 parseBlock();
160 addUnwrappedLine();
161 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000162 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000163 nextToken();
164 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
165 parseLabel();
166 return;
167 }
168 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000169 default:
170 nextToken();
171 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000172 }
173 } while (!eof());
174}
175
176void UnwrappedLineParser::parseParens() {
177 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
178 nextToken();
179 do {
180 switch (FormatTok.Tok.getKind()) {
181 case tok::l_paren:
182 parseParens();
183 break;
184 case tok::r_paren:
185 nextToken();
186 return;
187 default:
188 nextToken();
189 break;
190 }
191 } while (!eof());
192}
193
194void UnwrappedLineParser::parseIfThenElse() {
195 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
196 nextToken();
197 parseParens();
198 bool NeedsUnwrappedLine = false;
199 if (FormatTok.Tok.is(tok::l_brace)) {
200 parseBlock();
201 NeedsUnwrappedLine = true;
202 } else {
203 addUnwrappedLine();
204 ++Line.Level;
205 parseStatement();
206 --Line.Level;
207 }
208 if (FormatTok.Tok.is(tok::kw_else)) {
209 nextToken();
210 if (FormatTok.Tok.is(tok::l_brace)) {
211 parseBlock();
212 addUnwrappedLine();
213 } else if (FormatTok.Tok.is(tok::kw_if)) {
214 parseIfThenElse();
215 } else {
216 addUnwrappedLine();
217 ++Line.Level;
218 parseStatement();
219 --Line.Level;
220 }
221 } else if (NeedsUnwrappedLine) {
222 addUnwrappedLine();
223 }
224}
225
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000226void UnwrappedLineParser::parseForOrWhileLoop() {
227 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
228 "'for' or 'while' expected");
229 nextToken();
230 parseParens();
231 if (FormatTok.Tok.is(tok::l_brace)) {
232 parseBlock();
233 addUnwrappedLine();
234 } else {
235 addUnwrappedLine();
236 ++Line.Level;
237 parseStatement();
238 --Line.Level;
239 }
240}
241
Daniel Jasperbac016b2012-12-03 18:12:45 +0000242void UnwrappedLineParser::parseDoWhile() {
243 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
244 nextToken();
245 if (FormatTok.Tok.is(tok::l_brace)) {
246 parseBlock();
247 } else {
248 addUnwrappedLine();
249 ++Line.Level;
250 parseStatement();
251 --Line.Level;
252 }
253
Alexander Kornienko393b0082012-12-04 15:40:36 +0000254 // FIXME: Add error handling.
255 if (!FormatTok.Tok.is(tok::kw_while)) {
256 addUnwrappedLine();
257 return;
258 }
259
Daniel Jasperbac016b2012-12-03 18:12:45 +0000260 nextToken();
261 parseStatement();
262}
263
264void UnwrappedLineParser::parseLabel() {
265 // FIXME: remove all asserts.
266 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
267 nextToken();
268 unsigned OldLineLevel = Line.Level;
269 if (Line.Level > 0)
270 --Line.Level;
271 if (FormatTok.Tok.is(tok::l_brace)) {
272 parseBlock();
273 }
274 addUnwrappedLine();
275 Line.Level = OldLineLevel;
276}
277
278void UnwrappedLineParser::parseCaseLabel() {
279 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
280 // FIXME: fix handling of complex expressions here.
281 do {
282 nextToken();
283 } while (!eof() && !FormatTok.Tok.is(tok::colon));
284 parseLabel();
285}
286
287void UnwrappedLineParser::parseSwitch() {
288 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
289 nextToken();
290 parseParens();
291 if (FormatTok.Tok.is(tok::l_brace)) {
292 parseBlock();
293 addUnwrappedLine();
294 } else {
295 addUnwrappedLine();
296 ++Line.Level;
297 parseStatement();
298 --Line.Level;
299 }
300}
301
302void UnwrappedLineParser::parseAccessSpecifier() {
303 nextToken();
304 nextToken();
305 addUnwrappedLine();
306}
307
308void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000309 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000310 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000311 switch (FormatTok.Tok.getKind()) {
312 case tok::l_brace:
313 nextToken();
314 addUnwrappedLine();
315 ++Line.Level;
316 break;
317 case tok::l_paren:
318 parseParens();
319 break;
320 case tok::comma:
321 nextToken();
322 addUnwrappedLine();
323 break;
324 case tok::r_brace:
325 if (HasContents)
326 addUnwrappedLine();
327 --Line.Level;
328 nextToken();
329 break;
330 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000331 nextToken();
332 addUnwrappedLine();
333 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000334 default:
335 HasContents = true;
336 nextToken();
337 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000338 }
339 } while (!eof());
340}
341
342void UnwrappedLineParser::addUnwrappedLine() {
343 // Consume trailing comments.
344 while (!eof() && FormatTok.NewlinesBefore == 0 &&
345 FormatTok.Tok.is(tok::comment)) {
346 nextToken();
347 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000348 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000349 Line.Tokens.clear();
350}
351
352bool UnwrappedLineParser::eof() const {
353 return FormatTok.Tok.is(tok::eof);
354}
355
356void UnwrappedLineParser::nextToken() {
357 if (eof())
358 return;
359 Line.Tokens.push_back(FormatTok);
360 parseToken();
361}
362
363void UnwrappedLineParser::parseToken() {
364 if (GreaterStashed) {
365 FormatTok.NewlinesBefore = 0;
366 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
367 FormatTok.WhiteSpaceLength = 0;
368 GreaterStashed = false;
369 return;
370 }
371
372 FormatTok = FormatToken();
373 Lex.LexFromRawLexer(FormatTok.Tok);
374 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
375
376 // Consume and record whitespace until we find a significant token.
377 while (FormatTok.Tok.is(tok::unknown)) {
378 FormatTok.NewlinesBefore += tokenText().count('\n');
379 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
380
381 if (eof())
382 return;
383 Lex.LexFromRawLexer(FormatTok.Tok);
384 }
385
386 if (FormatTok.Tok.is(tok::raw_identifier)) {
387 const IdentifierInfo &Info = IdentTable.get(tokenText());
388 FormatTok.Tok.setKind(Info.getTokenID());
389 }
390
391 if (FormatTok.Tok.is(tok::greatergreater)) {
392 FormatTok.Tok.setKind(tok::greater);
393 GreaterStashed = true;
394 }
395}
396
397StringRef UnwrappedLineParser::tokenText() {
398 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
399 FormatTok.Tok.getLength());
400 return Data;
401}
402
403} // end namespace format
404} // end namespace clang