blob: 888f1c9eeb99621ac194178dc6da88e11aa0e5cd [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
35void UnwrappedLineParser::parse() {
36 parseToken();
37 parseLevel();
38}
39
40void UnwrappedLineParser::parseLevel() {
41 do {
42 switch (FormatTok.Tok.getKind()) {
43 case tok::hash:
44 parsePPDirective();
45 break;
46 case tok::comment:
47 parseComment();
48 break;
49 case tok::l_brace:
50 parseBlock();
51 addUnwrappedLine();
52 break;
53 case tok::r_brace:
54 return;
55 default:
56 parseStatement();
57 break;
58 }
59 } while (!eof());
60}
61
62void UnwrappedLineParser::parseBlock() {
63 nextToken();
64
65 // FIXME: Remove this hack to handle namespaces.
66 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
67
68 addUnwrappedLine();
69
70 if (!IsNamespace)
71 ++Line.Level;
72 parseLevel();
73 if (!IsNamespace)
74 --Line.Level;
Alexander Kornienko393b0082012-12-04 15:40:36 +000075 // FIXME: Add error handling.
76 if (!FormatTok.Tok.is(tok::r_brace))
77 return;
78
Daniel Jasperbac016b2012-12-03 18:12:45 +000079 nextToken();
80 if (FormatTok.Tok.is(tok::semi))
81 nextToken();
82}
83
84void UnwrappedLineParser::parsePPDirective() {
85 while (!eof()) {
86 nextToken();
87 if (FormatTok.NewlinesBefore > 0) {
88 addUnwrappedLine();
89 return;
90 }
91 }
92}
93
94void UnwrappedLineParser::parseComment() {
95 while (!eof()) {
96 nextToken();
97 if (FormatTok.NewlinesBefore > 0) {
98 addUnwrappedLine();
99 return;
100 }
101 }
102}
103
104void UnwrappedLineParser::parseStatement() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000105 switch (FormatTok.Tok.getKind()) {
106 case tok::kw_public:
107 case tok::kw_protected:
108 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000109 parseAccessSpecifier();
110 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000111 case tok::kw_if:
112 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000113 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000114 case tok::kw_do:
115 parseDoWhile();
116 return;
117 case tok::kw_switch:
118 parseSwitch();
119 return;
120 case tok::kw_default:
121 nextToken();
122 parseLabel();
123 return;
124 case tok::kw_case:
125 parseCaseLabel();
126 return;
127 default:
128 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000129 }
130 int TokenNumber = 0;
131 do {
132 ++TokenNumber;
133 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000134 case tok::kw_enum:
135 parseEnum();
136 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000137 case tok::semi:
138 nextToken();
139 addUnwrappedLine();
140 return;
141 case tok::l_paren:
142 parseParens();
143 break;
144 case tok::l_brace:
145 parseBlock();
146 addUnwrappedLine();
147 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000148 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000149 nextToken();
150 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
151 parseLabel();
152 return;
153 }
154 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000155 default:
156 nextToken();
157 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000158 }
159 } while (!eof());
160}
161
162void UnwrappedLineParser::parseParens() {
163 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
164 nextToken();
165 do {
166 switch (FormatTok.Tok.getKind()) {
167 case tok::l_paren:
168 parseParens();
169 break;
170 case tok::r_paren:
171 nextToken();
172 return;
173 default:
174 nextToken();
175 break;
176 }
177 } while (!eof());
178}
179
180void UnwrappedLineParser::parseIfThenElse() {
181 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
182 nextToken();
183 parseParens();
184 bool NeedsUnwrappedLine = false;
185 if (FormatTok.Tok.is(tok::l_brace)) {
186 parseBlock();
187 NeedsUnwrappedLine = true;
188 } else {
189 addUnwrappedLine();
190 ++Line.Level;
191 parseStatement();
192 --Line.Level;
193 }
194 if (FormatTok.Tok.is(tok::kw_else)) {
195 nextToken();
196 if (FormatTok.Tok.is(tok::l_brace)) {
197 parseBlock();
198 addUnwrappedLine();
199 } else if (FormatTok.Tok.is(tok::kw_if)) {
200 parseIfThenElse();
201 } else {
202 addUnwrappedLine();
203 ++Line.Level;
204 parseStatement();
205 --Line.Level;
206 }
207 } else if (NeedsUnwrappedLine) {
208 addUnwrappedLine();
209 }
210}
211
212void UnwrappedLineParser::parseDoWhile() {
213 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
214 nextToken();
215 if (FormatTok.Tok.is(tok::l_brace)) {
216 parseBlock();
217 } else {
218 addUnwrappedLine();
219 ++Line.Level;
220 parseStatement();
221 --Line.Level;
222 }
223
Alexander Kornienko393b0082012-12-04 15:40:36 +0000224 // FIXME: Add error handling.
225 if (!FormatTok.Tok.is(tok::kw_while)) {
226 addUnwrappedLine();
227 return;
228 }
229
Daniel Jasperbac016b2012-12-03 18:12:45 +0000230 nextToken();
231 parseStatement();
232}
233
234void UnwrappedLineParser::parseLabel() {
235 // FIXME: remove all asserts.
236 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
237 nextToken();
238 unsigned OldLineLevel = Line.Level;
239 if (Line.Level > 0)
240 --Line.Level;
241 if (FormatTok.Tok.is(tok::l_brace)) {
242 parseBlock();
243 }
244 addUnwrappedLine();
245 Line.Level = OldLineLevel;
246}
247
248void UnwrappedLineParser::parseCaseLabel() {
249 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
250 // FIXME: fix handling of complex expressions here.
251 do {
252 nextToken();
253 } while (!eof() && !FormatTok.Tok.is(tok::colon));
254 parseLabel();
255}
256
257void UnwrappedLineParser::parseSwitch() {
258 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
259 nextToken();
260 parseParens();
261 if (FormatTok.Tok.is(tok::l_brace)) {
262 parseBlock();
263 addUnwrappedLine();
264 } else {
265 addUnwrappedLine();
266 ++Line.Level;
267 parseStatement();
268 --Line.Level;
269 }
270}
271
272void UnwrappedLineParser::parseAccessSpecifier() {
273 nextToken();
274 nextToken();
275 addUnwrappedLine();
276}
277
278void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000279 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000280 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000281 switch (FormatTok.Tok.getKind()) {
282 case tok::l_brace:
283 nextToken();
284 addUnwrappedLine();
285 ++Line.Level;
286 break;
287 case tok::l_paren:
288 parseParens();
289 break;
290 case tok::comma:
291 nextToken();
292 addUnwrappedLine();
293 break;
294 case tok::r_brace:
295 if (HasContents)
296 addUnwrappedLine();
297 --Line.Level;
298 nextToken();
299 break;
300 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000301 nextToken();
302 addUnwrappedLine();
303 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000304 default:
305 HasContents = true;
306 nextToken();
307 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000308 }
309 } while (!eof());
310}
311
312void UnwrappedLineParser::addUnwrappedLine() {
313 // Consume trailing comments.
314 while (!eof() && FormatTok.NewlinesBefore == 0 &&
315 FormatTok.Tok.is(tok::comment)) {
316 nextToken();
317 }
318 Callback.formatUnwrappedLine(Line);
319 Line.Tokens.clear();
320}
321
322bool UnwrappedLineParser::eof() const {
323 return FormatTok.Tok.is(tok::eof);
324}
325
326void UnwrappedLineParser::nextToken() {
327 if (eof())
328 return;
329 Line.Tokens.push_back(FormatTok);
330 parseToken();
331}
332
333void UnwrappedLineParser::parseToken() {
334 if (GreaterStashed) {
335 FormatTok.NewlinesBefore = 0;
336 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
337 FormatTok.WhiteSpaceLength = 0;
338 GreaterStashed = false;
339 return;
340 }
341
342 FormatTok = FormatToken();
343 Lex.LexFromRawLexer(FormatTok.Tok);
344 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
345
346 // Consume and record whitespace until we find a significant token.
347 while (FormatTok.Tok.is(tok::unknown)) {
348 FormatTok.NewlinesBefore += tokenText().count('\n');
349 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
350
351 if (eof())
352 return;
353 Lex.LexFromRawLexer(FormatTok.Tok);
354 }
355
356 if (FormatTok.Tok.is(tok::raw_identifier)) {
357 const IdentifierInfo &Info = IdentTable.get(tokenText());
358 FormatTok.Tok.setKind(Info.getTokenID());
359 }
360
361 if (FormatTok.Tok.is(tok::greatergreater)) {
362 FormatTok.Tok.setKind(tok::greater);
363 GreaterStashed = true;
364 }
365}
366
367StringRef UnwrappedLineParser::tokenText() {
368 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
369 FormatTok.Tok.getLength());
370 return Data;
371}
372
373} // end namespace format
374} // end namespace clang