blob: 425e15b81f99dddaf41f5670a42b2616e2066a1b [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 Kornienkoa3a2b3a2012-12-06 17:49:17 +000055 // Stray '}' is an error.
56 return true;
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() {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000066 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +000067 nextToken();
68
69 // FIXME: Remove this hack to handle namespaces.
70 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
71
72 addUnwrappedLine();
73
74 if (!IsNamespace)
75 ++Line.Level;
76 parseLevel();
77 if (!IsNamespace)
78 --Line.Level;
Alexander Kornienko393b0082012-12-04 15:40:36 +000079 // FIXME: Add error handling.
80 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +000081 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +000082
Daniel Jasperbac016b2012-12-03 18:12:45 +000083 nextToken();
84 if (FormatTok.Tok.is(tok::semi))
85 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000086 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000087}
88
89void UnwrappedLineParser::parsePPDirective() {
90 while (!eof()) {
91 nextToken();
92 if (FormatTok.NewlinesBefore > 0) {
93 addUnwrappedLine();
94 return;
95 }
96 }
97}
98
99void UnwrappedLineParser::parseComment() {
100 while (!eof()) {
101 nextToken();
102 if (FormatTok.NewlinesBefore > 0) {
103 addUnwrappedLine();
104 return;
105 }
106 }
107}
108
109void UnwrappedLineParser::parseStatement() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000110 // Consume leading line comments, e.g. for branches without compounds.
111 while (FormatTok.Tok.is(tok::comment)) {
112 nextToken();
113 addUnwrappedLine();
114 }
115
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000116 switch (FormatTok.Tok.getKind()) {
117 case tok::kw_public:
118 case tok::kw_protected:
119 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000120 parseAccessSpecifier();
121 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000122 case tok::kw_if:
123 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000124 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000125 case tok::kw_for:
126 case tok::kw_while:
127 parseForOrWhileLoop();
128 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000129 case tok::kw_do:
130 parseDoWhile();
131 return;
132 case tok::kw_switch:
133 parseSwitch();
134 return;
135 case tok::kw_default:
136 nextToken();
137 parseLabel();
138 return;
139 case tok::kw_case:
140 parseCaseLabel();
141 return;
142 default:
143 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000144 }
145 int TokenNumber = 0;
146 do {
147 ++TokenNumber;
148 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000149 case tok::kw_enum:
150 parseEnum();
151 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000152 case tok::semi:
153 nextToken();
154 addUnwrappedLine();
155 return;
156 case tok::l_paren:
157 parseParens();
158 break;
159 case tok::l_brace:
160 parseBlock();
161 addUnwrappedLine();
162 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000163 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000164 nextToken();
165 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
166 parseLabel();
167 return;
168 }
169 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000170 default:
171 nextToken();
172 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000173 }
174 } while (!eof());
175}
176
177void UnwrappedLineParser::parseParens() {
178 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
179 nextToken();
180 do {
181 switch (FormatTok.Tok.getKind()) {
182 case tok::l_paren:
183 parseParens();
184 break;
185 case tok::r_paren:
186 nextToken();
187 return;
188 default:
189 nextToken();
190 break;
191 }
192 } while (!eof());
193}
194
195void UnwrappedLineParser::parseIfThenElse() {
196 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
197 nextToken();
198 parseParens();
199 bool NeedsUnwrappedLine = false;
200 if (FormatTok.Tok.is(tok::l_brace)) {
201 parseBlock();
202 NeedsUnwrappedLine = true;
203 } else {
204 addUnwrappedLine();
205 ++Line.Level;
206 parseStatement();
207 --Line.Level;
208 }
209 if (FormatTok.Tok.is(tok::kw_else)) {
210 nextToken();
211 if (FormatTok.Tok.is(tok::l_brace)) {
212 parseBlock();
213 addUnwrappedLine();
214 } else if (FormatTok.Tok.is(tok::kw_if)) {
215 parseIfThenElse();
216 } else {
217 addUnwrappedLine();
218 ++Line.Level;
219 parseStatement();
220 --Line.Level;
221 }
222 } else if (NeedsUnwrappedLine) {
223 addUnwrappedLine();
224 }
225}
226
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000227void UnwrappedLineParser::parseForOrWhileLoop() {
228 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
229 "'for' or 'while' expected");
230 nextToken();
231 parseParens();
232 if (FormatTok.Tok.is(tok::l_brace)) {
233 parseBlock();
234 addUnwrappedLine();
235 } else {
236 addUnwrappedLine();
237 ++Line.Level;
238 parseStatement();
239 --Line.Level;
240 }
241}
242
Daniel Jasperbac016b2012-12-03 18:12:45 +0000243void UnwrappedLineParser::parseDoWhile() {
244 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
245 nextToken();
246 if (FormatTok.Tok.is(tok::l_brace)) {
247 parseBlock();
248 } else {
249 addUnwrappedLine();
250 ++Line.Level;
251 parseStatement();
252 --Line.Level;
253 }
254
Alexander Kornienko393b0082012-12-04 15:40:36 +0000255 // FIXME: Add error handling.
256 if (!FormatTok.Tok.is(tok::kw_while)) {
257 addUnwrappedLine();
258 return;
259 }
260
Daniel Jasperbac016b2012-12-03 18:12:45 +0000261 nextToken();
262 parseStatement();
263}
264
265void UnwrappedLineParser::parseLabel() {
266 // FIXME: remove all asserts.
267 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
268 nextToken();
269 unsigned OldLineLevel = Line.Level;
270 if (Line.Level > 0)
271 --Line.Level;
272 if (FormatTok.Tok.is(tok::l_brace)) {
273 parseBlock();
274 }
275 addUnwrappedLine();
276 Line.Level = OldLineLevel;
277}
278
279void UnwrappedLineParser::parseCaseLabel() {
280 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
281 // FIXME: fix handling of complex expressions here.
282 do {
283 nextToken();
284 } while (!eof() && !FormatTok.Tok.is(tok::colon));
285 parseLabel();
286}
287
288void UnwrappedLineParser::parseSwitch() {
289 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
290 nextToken();
291 parseParens();
292 if (FormatTok.Tok.is(tok::l_brace)) {
293 parseBlock();
294 addUnwrappedLine();
295 } else {
296 addUnwrappedLine();
297 ++Line.Level;
298 parseStatement();
299 --Line.Level;
300 }
301}
302
303void UnwrappedLineParser::parseAccessSpecifier() {
304 nextToken();
305 nextToken();
306 addUnwrappedLine();
307}
308
309void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000310 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000311 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000312 switch (FormatTok.Tok.getKind()) {
313 case tok::l_brace:
314 nextToken();
315 addUnwrappedLine();
316 ++Line.Level;
317 break;
318 case tok::l_paren:
319 parseParens();
320 break;
321 case tok::comma:
322 nextToken();
323 addUnwrappedLine();
324 break;
325 case tok::r_brace:
326 if (HasContents)
327 addUnwrappedLine();
328 --Line.Level;
329 nextToken();
330 break;
331 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000332 nextToken();
333 addUnwrappedLine();
334 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000335 default:
336 HasContents = true;
337 nextToken();
338 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000339 }
340 } while (!eof());
341}
342
343void UnwrappedLineParser::addUnwrappedLine() {
344 // Consume trailing comments.
345 while (!eof() && FormatTok.NewlinesBefore == 0 &&
346 FormatTok.Tok.is(tok::comment)) {
347 nextToken();
348 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000349 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000350 Line.Tokens.clear();
351}
352
353bool UnwrappedLineParser::eof() const {
354 return FormatTok.Tok.is(tok::eof);
355}
356
357void UnwrappedLineParser::nextToken() {
358 if (eof())
359 return;
360 Line.Tokens.push_back(FormatTok);
361 parseToken();
362}
363
364void UnwrappedLineParser::parseToken() {
365 if (GreaterStashed) {
366 FormatTok.NewlinesBefore = 0;
367 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
368 FormatTok.WhiteSpaceLength = 0;
369 GreaterStashed = false;
370 return;
371 }
372
373 FormatTok = FormatToken();
374 Lex.LexFromRawLexer(FormatTok.Tok);
375 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
376
377 // Consume and record whitespace until we find a significant token.
378 while (FormatTok.Tok.is(tok::unknown)) {
379 FormatTok.NewlinesBefore += tokenText().count('\n');
380 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
381
382 if (eof())
383 return;
384 Lex.LexFromRawLexer(FormatTok.Tok);
385 }
386
387 if (FormatTok.Tok.is(tok::raw_identifier)) {
388 const IdentifierInfo &Info = IdentTable.get(tokenText());
389 FormatTok.Tok.setKind(Info.getTokenID());
390 }
391
392 if (FormatTok.Tok.is(tok::greatergreater)) {
393 FormatTok.Tok.setKind(tok::greater);
394 GreaterStashed = true;
395 }
396}
397
398StringRef UnwrappedLineParser::tokenText() {
399 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
400 FormatTok.Tok.getLength());
401 return Data;
402}
403
404} // end namespace format
405} // end namespace clang