blob: 7c04ce09dda936c6c4a2e34138a4a12b01cd6d97 [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;
75 assert(FormatTok.Tok.is(tok::r_brace) && "expected '}'");
76 nextToken();
77 if (FormatTok.Tok.is(tok::semi))
78 nextToken();
79}
80
81void UnwrappedLineParser::parsePPDirective() {
82 while (!eof()) {
83 nextToken();
84 if (FormatTok.NewlinesBefore > 0) {
85 addUnwrappedLine();
86 return;
87 }
88 }
89}
90
91void UnwrappedLineParser::parseComment() {
92 while (!eof()) {
93 nextToken();
94 if (FormatTok.NewlinesBefore > 0) {
95 addUnwrappedLine();
96 return;
97 }
98 }
99}
100
101void UnwrappedLineParser::parseStatement() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000102 switch (FormatTok.Tok.getKind()) {
103 case tok::kw_public:
104 case tok::kw_protected:
105 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000106 parseAccessSpecifier();
107 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000108 case tok::kw_if:
109 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000110 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000111 case tok::kw_do:
112 parseDoWhile();
113 return;
114 case tok::kw_switch:
115 parseSwitch();
116 return;
117 case tok::kw_default:
118 nextToken();
119 parseLabel();
120 return;
121 case tok::kw_case:
122 parseCaseLabel();
123 return;
124 default:
125 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000126 }
127 int TokenNumber = 0;
128 do {
129 ++TokenNumber;
130 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000131 case tok::kw_enum:
132 parseEnum();
133 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000134 case tok::semi:
135 nextToken();
136 addUnwrappedLine();
137 return;
138 case tok::l_paren:
139 parseParens();
140 break;
141 case tok::l_brace:
142 parseBlock();
143 addUnwrappedLine();
144 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000145 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000146 nextToken();
147 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
148 parseLabel();
149 return;
150 }
151 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000152 default:
153 nextToken();
154 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000155 }
156 } while (!eof());
157}
158
159void UnwrappedLineParser::parseParens() {
160 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
161 nextToken();
162 do {
163 switch (FormatTok.Tok.getKind()) {
164 case tok::l_paren:
165 parseParens();
166 break;
167 case tok::r_paren:
168 nextToken();
169 return;
170 default:
171 nextToken();
172 break;
173 }
174 } while (!eof());
175}
176
177void UnwrappedLineParser::parseIfThenElse() {
178 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
179 nextToken();
180 parseParens();
181 bool NeedsUnwrappedLine = false;
182 if (FormatTok.Tok.is(tok::l_brace)) {
183 parseBlock();
184 NeedsUnwrappedLine = true;
185 } else {
186 addUnwrappedLine();
187 ++Line.Level;
188 parseStatement();
189 --Line.Level;
190 }
191 if (FormatTok.Tok.is(tok::kw_else)) {
192 nextToken();
193 if (FormatTok.Tok.is(tok::l_brace)) {
194 parseBlock();
195 addUnwrappedLine();
196 } else if (FormatTok.Tok.is(tok::kw_if)) {
197 parseIfThenElse();
198 } else {
199 addUnwrappedLine();
200 ++Line.Level;
201 parseStatement();
202 --Line.Level;
203 }
204 } else if (NeedsUnwrappedLine) {
205 addUnwrappedLine();
206 }
207}
208
209void UnwrappedLineParser::parseDoWhile() {
210 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
211 nextToken();
212 if (FormatTok.Tok.is(tok::l_brace)) {
213 parseBlock();
214 } else {
215 addUnwrappedLine();
216 ++Line.Level;
217 parseStatement();
218 --Line.Level;
219 }
220
221 assert(FormatTok.Tok.is(tok::kw_while) && "'while' expected");
222 nextToken();
223 parseStatement();
224}
225
226void UnwrappedLineParser::parseLabel() {
227 // FIXME: remove all asserts.
228 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
229 nextToken();
230 unsigned OldLineLevel = Line.Level;
231 if (Line.Level > 0)
232 --Line.Level;
233 if (FormatTok.Tok.is(tok::l_brace)) {
234 parseBlock();
235 }
236 addUnwrappedLine();
237 Line.Level = OldLineLevel;
238}
239
240void UnwrappedLineParser::parseCaseLabel() {
241 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
242 // FIXME: fix handling of complex expressions here.
243 do {
244 nextToken();
245 } while (!eof() && !FormatTok.Tok.is(tok::colon));
246 parseLabel();
247}
248
249void UnwrappedLineParser::parseSwitch() {
250 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
251 nextToken();
252 parseParens();
253 if (FormatTok.Tok.is(tok::l_brace)) {
254 parseBlock();
255 addUnwrappedLine();
256 } else {
257 addUnwrappedLine();
258 ++Line.Level;
259 parseStatement();
260 --Line.Level;
261 }
262}
263
264void UnwrappedLineParser::parseAccessSpecifier() {
265 nextToken();
266 nextToken();
267 addUnwrappedLine();
268}
269
270void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000271 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000272 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000273 switch (FormatTok.Tok.getKind()) {
274 case tok::l_brace:
275 nextToken();
276 addUnwrappedLine();
277 ++Line.Level;
278 break;
279 case tok::l_paren:
280 parseParens();
281 break;
282 case tok::comma:
283 nextToken();
284 addUnwrappedLine();
285 break;
286 case tok::r_brace:
287 if (HasContents)
288 addUnwrappedLine();
289 --Line.Level;
290 nextToken();
291 break;
292 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000293 nextToken();
294 addUnwrappedLine();
295 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000296 default:
297 HasContents = true;
298 nextToken();
299 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000300 }
301 } while (!eof());
302}
303
304void UnwrappedLineParser::addUnwrappedLine() {
305 // Consume trailing comments.
306 while (!eof() && FormatTok.NewlinesBefore == 0 &&
307 FormatTok.Tok.is(tok::comment)) {
308 nextToken();
309 }
310 Callback.formatUnwrappedLine(Line);
311 Line.Tokens.clear();
312}
313
314bool UnwrappedLineParser::eof() const {
315 return FormatTok.Tok.is(tok::eof);
316}
317
318void UnwrappedLineParser::nextToken() {
319 if (eof())
320 return;
321 Line.Tokens.push_back(FormatTok);
322 parseToken();
323}
324
325void UnwrappedLineParser::parseToken() {
326 if (GreaterStashed) {
327 FormatTok.NewlinesBefore = 0;
328 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
329 FormatTok.WhiteSpaceLength = 0;
330 GreaterStashed = false;
331 return;
332 }
333
334 FormatTok = FormatToken();
335 Lex.LexFromRawLexer(FormatTok.Tok);
336 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
337
338 // Consume and record whitespace until we find a significant token.
339 while (FormatTok.Tok.is(tok::unknown)) {
340 FormatTok.NewlinesBefore += tokenText().count('\n');
341 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
342
343 if (eof())
344 return;
345 Lex.LexFromRawLexer(FormatTok.Tok);
346 }
347
348 if (FormatTok.Tok.is(tok::raw_identifier)) {
349 const IdentifierInfo &Info = IdentTable.get(tokenText());
350 FormatTok.Tok.setKind(Info.getTokenID());
351 }
352
353 if (FormatTok.Tok.is(tok::greatergreater)) {
354 FormatTok.Tok.setKind(tok::greater);
355 GreaterStashed = true;
356 }
357}
358
359StringRef UnwrappedLineParser::tokenText() {
360 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
361 FormatTok.Tok.getLength());
362 return Data;
363}
364
365} // end namespace format
366} // end namespace clang