blob: bdea42a2eb4469e848e5cbfdbbfc0d953ddf63cb [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 Kornienko720ffb62012-12-05 13:56:52 +000055 // FIXME: We need a test when it has to be "return Error;"
Alexander Kornienkocff563c2012-12-04 17:27:50 +000056 return false;
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() {
Daniel Jasperbac016b2012-12-03 18:12:45 +000066 nextToken();
67
68 // FIXME: Remove this hack to handle namespaces.
69 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
70
71 addUnwrappedLine();
72
73 if (!IsNamespace)
74 ++Line.Level;
75 parseLevel();
76 if (!IsNamespace)
77 --Line.Level;
Alexander Kornienko393b0082012-12-04 15:40:36 +000078 // FIXME: Add error handling.
79 if (!FormatTok.Tok.is(tok::r_brace))
Alexander Kornienkocff563c2012-12-04 17:27:50 +000080 return true;
Alexander Kornienko393b0082012-12-04 15:40:36 +000081
Daniel Jasperbac016b2012-12-03 18:12:45 +000082 nextToken();
83 if (FormatTok.Tok.is(tok::semi))
84 nextToken();
Alexander Kornienkocff563c2012-12-04 17:27:50 +000085 return false;
Daniel Jasperbac016b2012-12-03 18:12:45 +000086}
87
88void UnwrappedLineParser::parsePPDirective() {
89 while (!eof()) {
90 nextToken();
91 if (FormatTok.NewlinesBefore > 0) {
92 addUnwrappedLine();
93 return;
94 }
95 }
96}
97
98void UnwrappedLineParser::parseComment() {
99 while (!eof()) {
100 nextToken();
101 if (FormatTok.NewlinesBefore > 0) {
102 addUnwrappedLine();
103 return;
104 }
105 }
106}
107
108void UnwrappedLineParser::parseStatement() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000109 switch (FormatTok.Tok.getKind()) {
110 case tok::kw_public:
111 case tok::kw_protected:
112 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000113 parseAccessSpecifier();
114 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000115 case tok::kw_if:
116 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000117 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000118 case tok::kw_do:
119 parseDoWhile();
120 return;
121 case tok::kw_switch:
122 parseSwitch();
123 return;
124 case tok::kw_default:
125 nextToken();
126 parseLabel();
127 return;
128 case tok::kw_case:
129 parseCaseLabel();
130 return;
131 default:
132 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000133 }
134 int TokenNumber = 0;
135 do {
136 ++TokenNumber;
137 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000138 case tok::kw_enum:
139 parseEnum();
140 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000141 case tok::semi:
142 nextToken();
143 addUnwrappedLine();
144 return;
145 case tok::l_paren:
146 parseParens();
147 break;
148 case tok::l_brace:
149 parseBlock();
150 addUnwrappedLine();
151 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000152 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000153 nextToken();
154 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
155 parseLabel();
156 return;
157 }
158 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000159 default:
160 nextToken();
161 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000162 }
163 } while (!eof());
164}
165
166void UnwrappedLineParser::parseParens() {
167 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
168 nextToken();
169 do {
170 switch (FormatTok.Tok.getKind()) {
171 case tok::l_paren:
172 parseParens();
173 break;
174 case tok::r_paren:
175 nextToken();
176 return;
177 default:
178 nextToken();
179 break;
180 }
181 } while (!eof());
182}
183
184void UnwrappedLineParser::parseIfThenElse() {
185 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
186 nextToken();
187 parseParens();
188 bool NeedsUnwrappedLine = false;
189 if (FormatTok.Tok.is(tok::l_brace)) {
190 parseBlock();
191 NeedsUnwrappedLine = true;
192 } else {
193 addUnwrappedLine();
194 ++Line.Level;
195 parseStatement();
196 --Line.Level;
197 }
198 if (FormatTok.Tok.is(tok::kw_else)) {
199 nextToken();
200 if (FormatTok.Tok.is(tok::l_brace)) {
201 parseBlock();
202 addUnwrappedLine();
203 } else if (FormatTok.Tok.is(tok::kw_if)) {
204 parseIfThenElse();
205 } else {
206 addUnwrappedLine();
207 ++Line.Level;
208 parseStatement();
209 --Line.Level;
210 }
211 } else if (NeedsUnwrappedLine) {
212 addUnwrappedLine();
213 }
214}
215
216void UnwrappedLineParser::parseDoWhile() {
217 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
218 nextToken();
219 if (FormatTok.Tok.is(tok::l_brace)) {
220 parseBlock();
221 } else {
222 addUnwrappedLine();
223 ++Line.Level;
224 parseStatement();
225 --Line.Level;
226 }
227
Alexander Kornienko393b0082012-12-04 15:40:36 +0000228 // FIXME: Add error handling.
229 if (!FormatTok.Tok.is(tok::kw_while)) {
230 addUnwrappedLine();
231 return;
232 }
233
Daniel Jasperbac016b2012-12-03 18:12:45 +0000234 nextToken();
235 parseStatement();
236}
237
238void UnwrappedLineParser::parseLabel() {
239 // FIXME: remove all asserts.
240 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
241 nextToken();
242 unsigned OldLineLevel = Line.Level;
243 if (Line.Level > 0)
244 --Line.Level;
245 if (FormatTok.Tok.is(tok::l_brace)) {
246 parseBlock();
247 }
248 addUnwrappedLine();
249 Line.Level = OldLineLevel;
250}
251
252void UnwrappedLineParser::parseCaseLabel() {
253 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
254 // FIXME: fix handling of complex expressions here.
255 do {
256 nextToken();
257 } while (!eof() && !FormatTok.Tok.is(tok::colon));
258 parseLabel();
259}
260
261void UnwrappedLineParser::parseSwitch() {
262 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
263 nextToken();
264 parseParens();
265 if (FormatTok.Tok.is(tok::l_brace)) {
266 parseBlock();
267 addUnwrappedLine();
268 } else {
269 addUnwrappedLine();
270 ++Line.Level;
271 parseStatement();
272 --Line.Level;
273 }
274}
275
276void UnwrappedLineParser::parseAccessSpecifier() {
277 nextToken();
278 nextToken();
279 addUnwrappedLine();
280}
281
282void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000283 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000284 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000285 switch (FormatTok.Tok.getKind()) {
286 case tok::l_brace:
287 nextToken();
288 addUnwrappedLine();
289 ++Line.Level;
290 break;
291 case tok::l_paren:
292 parseParens();
293 break;
294 case tok::comma:
295 nextToken();
296 addUnwrappedLine();
297 break;
298 case tok::r_brace:
299 if (HasContents)
300 addUnwrappedLine();
301 --Line.Level;
302 nextToken();
303 break;
304 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000305 nextToken();
306 addUnwrappedLine();
307 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000308 default:
309 HasContents = true;
310 nextToken();
311 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000312 }
313 } while (!eof());
314}
315
316void UnwrappedLineParser::addUnwrappedLine() {
317 // Consume trailing comments.
318 while (!eof() && FormatTok.NewlinesBefore == 0 &&
319 FormatTok.Tok.is(tok::comment)) {
320 nextToken();
321 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000322 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000323 Line.Tokens.clear();
324}
325
326bool UnwrappedLineParser::eof() const {
327 return FormatTok.Tok.is(tok::eof);
328}
329
330void UnwrappedLineParser::nextToken() {
331 if (eof())
332 return;
333 Line.Tokens.push_back(FormatTok);
334 parseToken();
335}
336
337void UnwrappedLineParser::parseToken() {
338 if (GreaterStashed) {
339 FormatTok.NewlinesBefore = 0;
340 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
341 FormatTok.WhiteSpaceLength = 0;
342 GreaterStashed = false;
343 return;
344 }
345
346 FormatTok = FormatToken();
347 Lex.LexFromRawLexer(FormatTok.Tok);
348 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
349
350 // Consume and record whitespace until we find a significant token.
351 while (FormatTok.Tok.is(tok::unknown)) {
352 FormatTok.NewlinesBefore += tokenText().count('\n');
353 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
354
355 if (eof())
356 return;
357 Lex.LexFromRawLexer(FormatTok.Tok);
358 }
359
360 if (FormatTok.Tok.is(tok::raw_identifier)) {
361 const IdentifierInfo &Info = IdentTable.get(tokenText());
362 FormatTok.Tok.setKind(Info.getTokenID());
363 }
364
365 if (FormatTok.Tok.is(tok::greatergreater)) {
366 FormatTok.Tok.setKind(tok::greater);
367 GreaterStashed = true;
368 }
369}
370
371StringRef UnwrappedLineParser::tokenText() {
372 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
373 FormatTok.Tok.getLength());
374 return Data;
375}
376
377} // end namespace format
378} // end namespace clang