blob: ebebece7eb435622fb580beefdb2b26ec9764572 [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 Kornienko15757312012-12-06 18:03:27 +000025UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style, Lexer &Lex,
26 SourceManager &SourceMgr,
Daniel Jasperbac016b2012-12-03 18:12:45 +000027 UnwrappedLineConsumer &Callback)
28 : GreaterStashed(false),
Alexander Kornienko15757312012-12-06 18:03:27 +000029 Style(Style),
Daniel Jasperbac016b2012-12-03 18:12:45 +000030 Lex(Lex),
31 SourceMgr(SourceMgr),
32 IdentTable(Lex.getLangOpts()),
33 Callback(Callback) {
34 Lex.SetKeepWhitespaceMode(true);
35}
36
Alexander Kornienkocff563c2012-12-04 17:27:50 +000037bool UnwrappedLineParser::parse() {
Daniel Jasperbac016b2012-12-03 18:12:45 +000038 parseToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000039 return parseLevel();
Daniel Jasperbac016b2012-12-03 18:12:45 +000040}
41
Alexander Kornienkocff563c2012-12-04 17:27:50 +000042bool UnwrappedLineParser::parseLevel() {
43 bool Error = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000044 do {
45 switch (FormatTok.Tok.getKind()) {
46 case tok::hash:
47 parsePPDirective();
48 break;
49 case tok::comment:
50 parseComment();
51 break;
52 case tok::l_brace:
Alexander Kornienkocff563c2012-12-04 17:27:50 +000053 Error |= parseBlock();
Daniel Jasperbac016b2012-12-03 18:12:45 +000054 addUnwrappedLine();
55 break;
56 case tok::r_brace:
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000057 // Stray '}' is an error.
58 return true;
Daniel Jasperbac016b2012-12-03 18:12:45 +000059 default:
60 parseStatement();
61 break;
62 }
63 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +000064 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000065}
66
Alexander Kornienko15757312012-12-06 18:03:27 +000067bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
Alexander Kornienkoa3a2b3a2012-12-06 17:49:17 +000068 assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
Daniel Jasperbac016b2012-12-03 18:12:45 +000069 nextToken();
70
Daniel Jasperbac016b2012-12-03 18:12:45 +000071 addUnwrappedLine();
72
Alexander Kornienko15757312012-12-06 18:03:27 +000073 Line.Level += AddLevels;
Daniel Jasperbac016b2012-12-03 18:12:45 +000074 parseLevel();
Alexander Kornienko15757312012-12-06 18:03:27 +000075 Line.Level -= AddLevels;
76
Alexander Kornienko393b0082012-12-04 15:40:36 +000077 // FIXME: Add error handling.
78 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +000079 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +000080
Daniel Jasperbac016b2012-12-03 18:12:45 +000081 nextToken();
82 if (FormatTok.Tok.is(tok::semi))
83 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000084 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000085}
86
87void UnwrappedLineParser::parsePPDirective() {
88 while (!eof()) {
89 nextToken();
90 if (FormatTok.NewlinesBefore > 0) {
91 addUnwrappedLine();
92 return;
93 }
94 }
95}
96
97void UnwrappedLineParser::parseComment() {
98 while (!eof()) {
99 nextToken();
100 if (FormatTok.NewlinesBefore > 0) {
101 addUnwrappedLine();
102 return;
103 }
104 }
105}
106
107void UnwrappedLineParser::parseStatement() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000108 // Consume leading line comments, e.g. for branches without compounds.
109 while (FormatTok.Tok.is(tok::comment)) {
110 nextToken();
111 addUnwrappedLine();
112 }
113
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000114 switch (FormatTok.Tok.getKind()) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000115 case tok::kw_namespace:
116 parseNamespace();
117 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000118 case tok::kw_public:
119 case tok::kw_protected:
120 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000121 parseAccessSpecifier();
122 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000123 case tok::kw_if:
124 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000125 return;
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000126 case tok::kw_for:
127 case tok::kw_while:
128 parseForOrWhileLoop();
129 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000130 case tok::kw_do:
131 parseDoWhile();
132 return;
133 case tok::kw_switch:
134 parseSwitch();
135 return;
136 case tok::kw_default:
137 nextToken();
138 parseLabel();
139 return;
140 case tok::kw_case:
141 parseCaseLabel();
142 return;
143 default:
144 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000145 }
146 int TokenNumber = 0;
147 do {
148 ++TokenNumber;
149 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000150 case tok::kw_enum:
151 parseEnum();
152 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000153 case tok::semi:
154 nextToken();
155 addUnwrappedLine();
156 return;
157 case tok::l_paren:
158 parseParens();
159 break;
160 case tok::l_brace:
161 parseBlock();
162 addUnwrappedLine();
163 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000164 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000165 nextToken();
166 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
167 parseLabel();
168 return;
169 }
170 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000171 default:
172 nextToken();
173 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000174 }
175 } while (!eof());
176}
177
178void UnwrappedLineParser::parseParens() {
179 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
180 nextToken();
181 do {
182 switch (FormatTok.Tok.getKind()) {
183 case tok::l_paren:
184 parseParens();
185 break;
186 case tok::r_paren:
187 nextToken();
188 return;
189 default:
190 nextToken();
191 break;
192 }
193 } while (!eof());
194}
195
196void UnwrappedLineParser::parseIfThenElse() {
197 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
198 nextToken();
199 parseParens();
200 bool NeedsUnwrappedLine = false;
201 if (FormatTok.Tok.is(tok::l_brace)) {
202 parseBlock();
203 NeedsUnwrappedLine = true;
204 } else {
205 addUnwrappedLine();
206 ++Line.Level;
207 parseStatement();
208 --Line.Level;
209 }
210 if (FormatTok.Tok.is(tok::kw_else)) {
211 nextToken();
212 if (FormatTok.Tok.is(tok::l_brace)) {
213 parseBlock();
214 addUnwrappedLine();
215 } else if (FormatTok.Tok.is(tok::kw_if)) {
216 parseIfThenElse();
217 } else {
218 addUnwrappedLine();
219 ++Line.Level;
220 parseStatement();
221 --Line.Level;
222 }
223 } else if (NeedsUnwrappedLine) {
224 addUnwrappedLine();
225 }
226}
227
Alexander Kornienko15757312012-12-06 18:03:27 +0000228void UnwrappedLineParser::parseNamespace() {
229 assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
230 nextToken();
231 if (FormatTok.Tok.is(tok::identifier))
232 nextToken();
233 if (FormatTok.Tok.is(tok::l_brace)) {
234 parseBlock(0);
235 addUnwrappedLine();
236 }
237 // FIXME: Add error handling.
238}
239
Alexander Kornienko2e97cfc2012-12-05 15:06:06 +0000240void UnwrappedLineParser::parseForOrWhileLoop() {
241 assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
242 "'for' or 'while' expected");
243 nextToken();
244 parseParens();
245 if (FormatTok.Tok.is(tok::l_brace)) {
246 parseBlock();
247 addUnwrappedLine();
248 } else {
249 addUnwrappedLine();
250 ++Line.Level;
251 parseStatement();
252 --Line.Level;
253 }
254}
255
Daniel Jasperbac016b2012-12-03 18:12:45 +0000256void UnwrappedLineParser::parseDoWhile() {
257 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
258 nextToken();
259 if (FormatTok.Tok.is(tok::l_brace)) {
260 parseBlock();
261 } else {
262 addUnwrappedLine();
263 ++Line.Level;
264 parseStatement();
265 --Line.Level;
266 }
267
Alexander Kornienko393b0082012-12-04 15:40:36 +0000268 // FIXME: Add error handling.
269 if (!FormatTok.Tok.is(tok::kw_while)) {
270 addUnwrappedLine();
271 return;
272 }
273
Daniel Jasperbac016b2012-12-03 18:12:45 +0000274 nextToken();
275 parseStatement();
276}
277
278void UnwrappedLineParser::parseLabel() {
279 // FIXME: remove all asserts.
280 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
281 nextToken();
282 unsigned OldLineLevel = Line.Level;
283 if (Line.Level > 0)
284 --Line.Level;
285 if (FormatTok.Tok.is(tok::l_brace)) {
286 parseBlock();
287 }
288 addUnwrappedLine();
289 Line.Level = OldLineLevel;
290}
291
292void UnwrappedLineParser::parseCaseLabel() {
293 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
294 // FIXME: fix handling of complex expressions here.
295 do {
296 nextToken();
297 } while (!eof() && !FormatTok.Tok.is(tok::colon));
298 parseLabel();
299}
300
301void UnwrappedLineParser::parseSwitch() {
302 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
303 nextToken();
304 parseParens();
305 if (FormatTok.Tok.is(tok::l_brace)) {
Alexander Kornienko15757312012-12-06 18:03:27 +0000306 parseBlock(Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000307 addUnwrappedLine();
308 } else {
309 addUnwrappedLine();
Alexander Kornienko15757312012-12-06 18:03:27 +0000310 Line.Level += (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000311 parseStatement();
Alexander Kornienko15757312012-12-06 18:03:27 +0000312 Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000313 }
314}
315
316void UnwrappedLineParser::parseAccessSpecifier() {
317 nextToken();
318 nextToken();
319 addUnwrappedLine();
320}
321
322void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000323 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000324 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000325 switch (FormatTok.Tok.getKind()) {
326 case tok::l_brace:
327 nextToken();
328 addUnwrappedLine();
329 ++Line.Level;
330 break;
331 case tok::l_paren:
332 parseParens();
333 break;
334 case tok::comma:
335 nextToken();
336 addUnwrappedLine();
337 break;
338 case tok::r_brace:
339 if (HasContents)
340 addUnwrappedLine();
341 --Line.Level;
342 nextToken();
343 break;
344 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000345 nextToken();
346 addUnwrappedLine();
347 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000348 default:
349 HasContents = true;
350 nextToken();
351 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000352 }
353 } while (!eof());
354}
355
356void UnwrappedLineParser::addUnwrappedLine() {
357 // Consume trailing comments.
358 while (!eof() && FormatTok.NewlinesBefore == 0 &&
359 FormatTok.Tok.is(tok::comment)) {
360 nextToken();
361 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000362 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000363 Line.Tokens.clear();
364}
365
366bool UnwrappedLineParser::eof() const {
367 return FormatTok.Tok.is(tok::eof);
368}
369
370void UnwrappedLineParser::nextToken() {
371 if (eof())
372 return;
373 Line.Tokens.push_back(FormatTok);
374 parseToken();
375}
376
377void UnwrappedLineParser::parseToken() {
378 if (GreaterStashed) {
379 FormatTok.NewlinesBefore = 0;
380 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
381 FormatTok.WhiteSpaceLength = 0;
382 GreaterStashed = false;
383 return;
384 }
385
386 FormatTok = FormatToken();
387 Lex.LexFromRawLexer(FormatTok.Tok);
388 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
389
390 // Consume and record whitespace until we find a significant token.
391 while (FormatTok.Tok.is(tok::unknown)) {
392 FormatTok.NewlinesBefore += tokenText().count('\n');
393 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
394
395 if (eof())
396 return;
397 Lex.LexFromRawLexer(FormatTok.Tok);
398 }
399
400 if (FormatTok.Tok.is(tok::raw_identifier)) {
401 const IdentifierInfo &Info = IdentTable.get(tokenText());
402 FormatTok.Tok.setKind(Info.getTokenID());
403 }
404
405 if (FormatTok.Tok.is(tok::greatergreater)) {
406 FormatTok.Tok.setKind(tok::greater);
407 GreaterStashed = true;
408 }
409}
410
411StringRef UnwrappedLineParser::tokenText() {
412 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
413 FormatTok.Tok.getLength());
414 return Data;
415}
416
417} // end namespace format
418} // end namespace clang