blob: e1972e9dd85ba26d57aba5025a8f848b7ad5fd03 [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 Kornienkocff563c2012-12-04 17:27:50 +000055 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000056 default:
57 parseStatement();
58 break;
59 }
60 } while (!eof());
Alexander Kornienkocff563c2012-12-04 17:27:50 +000061 return Error;
Daniel Jasperbac016b2012-12-03 18:12:45 +000062}
63
Alexander Kornienkocff563c2012-12-04 17:27:50 +000064bool UnwrappedLineParser::parseBlock() {
Daniel Jasperbac016b2012-12-03 18:12:45 +000065 nextToken();
66
67 // FIXME: Remove this hack to handle namespaces.
68 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
69
70 addUnwrappedLine();
71
72 if (!IsNamespace)
73 ++Line.Level;
74 parseLevel();
75 if (!IsNamespace)
76 --Line.Level;
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() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000108 switch (FormatTok.Tok.getKind()) {
109 case tok::kw_public:
110 case tok::kw_protected:
111 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000112 parseAccessSpecifier();
113 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000114 case tok::kw_if:
115 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000116 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000117 case tok::kw_do:
118 parseDoWhile();
119 return;
120 case tok::kw_switch:
121 parseSwitch();
122 return;
123 case tok::kw_default:
124 nextToken();
125 parseLabel();
126 return;
127 case tok::kw_case:
128 parseCaseLabel();
129 return;
130 default:
131 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000132 }
133 int TokenNumber = 0;
134 do {
135 ++TokenNumber;
136 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000137 case tok::kw_enum:
138 parseEnum();
139 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000140 case tok::semi:
141 nextToken();
142 addUnwrappedLine();
143 return;
144 case tok::l_paren:
145 parseParens();
146 break;
147 case tok::l_brace:
148 parseBlock();
149 addUnwrappedLine();
150 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000151 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000152 nextToken();
153 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
154 parseLabel();
155 return;
156 }
157 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000158 default:
159 nextToken();
160 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000161 }
162 } while (!eof());
163}
164
165void UnwrappedLineParser::parseParens() {
166 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
167 nextToken();
168 do {
169 switch (FormatTok.Tok.getKind()) {
170 case tok::l_paren:
171 parseParens();
172 break;
173 case tok::r_paren:
174 nextToken();
175 return;
176 default:
177 nextToken();
178 break;
179 }
180 } while (!eof());
181}
182
183void UnwrappedLineParser::parseIfThenElse() {
184 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
185 nextToken();
186 parseParens();
187 bool NeedsUnwrappedLine = false;
188 if (FormatTok.Tok.is(tok::l_brace)) {
189 parseBlock();
190 NeedsUnwrappedLine = true;
191 } else {
192 addUnwrappedLine();
193 ++Line.Level;
194 parseStatement();
195 --Line.Level;
196 }
197 if (FormatTok.Tok.is(tok::kw_else)) {
198 nextToken();
199 if (FormatTok.Tok.is(tok::l_brace)) {
200 parseBlock();
201 addUnwrappedLine();
202 } else if (FormatTok.Tok.is(tok::kw_if)) {
203 parseIfThenElse();
204 } else {
205 addUnwrappedLine();
206 ++Line.Level;
207 parseStatement();
208 --Line.Level;
209 }
210 } else if (NeedsUnwrappedLine) {
211 addUnwrappedLine();
212 }
213}
214
215void UnwrappedLineParser::parseDoWhile() {
216 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
217 nextToken();
218 if (FormatTok.Tok.is(tok::l_brace)) {
219 parseBlock();
220 } else {
221 addUnwrappedLine();
222 ++Line.Level;
223 parseStatement();
224 --Line.Level;
225 }
226
Alexander Kornienko393b0082012-12-04 15:40:36 +0000227 // FIXME: Add error handling.
228 if (!FormatTok.Tok.is(tok::kw_while)) {
229 addUnwrappedLine();
230 return;
231 }
232
Daniel Jasperbac016b2012-12-03 18:12:45 +0000233 nextToken();
234 parseStatement();
235}
236
237void UnwrappedLineParser::parseLabel() {
238 // FIXME: remove all asserts.
239 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
240 nextToken();
241 unsigned OldLineLevel = Line.Level;
242 if (Line.Level > 0)
243 --Line.Level;
244 if (FormatTok.Tok.is(tok::l_brace)) {
245 parseBlock();
246 }
247 addUnwrappedLine();
248 Line.Level = OldLineLevel;
249}
250
251void UnwrappedLineParser::parseCaseLabel() {
252 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
253 // FIXME: fix handling of complex expressions here.
254 do {
255 nextToken();
256 } while (!eof() && !FormatTok.Tok.is(tok::colon));
257 parseLabel();
258}
259
260void UnwrappedLineParser::parseSwitch() {
261 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
262 nextToken();
263 parseParens();
264 if (FormatTok.Tok.is(tok::l_brace)) {
265 parseBlock();
266 addUnwrappedLine();
267 } else {
268 addUnwrappedLine();
269 ++Line.Level;
270 parseStatement();
271 --Line.Level;
272 }
273}
274
275void UnwrappedLineParser::parseAccessSpecifier() {
276 nextToken();
277 nextToken();
278 addUnwrappedLine();
279}
280
281void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000282 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000283 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000284 switch (FormatTok.Tok.getKind()) {
285 case tok::l_brace:
286 nextToken();
287 addUnwrappedLine();
288 ++Line.Level;
289 break;
290 case tok::l_paren:
291 parseParens();
292 break;
293 case tok::comma:
294 nextToken();
295 addUnwrappedLine();
296 break;
297 case tok::r_brace:
298 if (HasContents)
299 addUnwrappedLine();
300 --Line.Level;
301 nextToken();
302 break;
303 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000304 nextToken();
305 addUnwrappedLine();
306 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000307 default:
308 HasContents = true;
309 nextToken();
310 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000311 }
312 } while (!eof());
313}
314
315void UnwrappedLineParser::addUnwrappedLine() {
316 // Consume trailing comments.
317 while (!eof() && FormatTok.NewlinesBefore == 0 &&
318 FormatTok.Tok.is(tok::comment)) {
319 nextToken();
320 }
321 Callback.formatUnwrappedLine(Line);
322 Line.Tokens.clear();
323}
324
325bool UnwrappedLineParser::eof() const {
326 return FormatTok.Tok.is(tok::eof);
327}
328
329void UnwrappedLineParser::nextToken() {
330 if (eof())
331 return;
332 Line.Tokens.push_back(FormatTok);
333 parseToken();
334}
335
336void UnwrappedLineParser::parseToken() {
337 if (GreaterStashed) {
338 FormatTok.NewlinesBefore = 0;
339 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
340 FormatTok.WhiteSpaceLength = 0;
341 GreaterStashed = false;
342 return;
343 }
344
345 FormatTok = FormatToken();
346 Lex.LexFromRawLexer(FormatTok.Tok);
347 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
348
349 // Consume and record whitespace until we find a significant token.
350 while (FormatTok.Tok.is(tok::unknown)) {
351 FormatTok.NewlinesBefore += tokenText().count('\n');
352 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
353
354 if (eof())
355 return;
356 Lex.LexFromRawLexer(FormatTok.Tok);
357 }
358
359 if (FormatTok.Tok.is(tok::raw_identifier)) {
360 const IdentifierInfo &Info = IdentTable.get(tokenText());
361 FormatTok.Tok.setKind(Info.getTokenID());
362 }
363
364 if (FormatTok.Tok.is(tok::greatergreater)) {
365 FormatTok.Tok.setKind(tok::greater);
366 GreaterStashed = true;
367 }
368}
369
370StringRef UnwrappedLineParser::tokenText() {
371 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
372 FormatTok.Tok.getLength());
373 return Data;
374}
375
376} // end namespace format
377} // end namespace clang