blob: c2cb5b8027bc1441fa6bab5e87c07f25de78e4ee [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() {
Daniel Jasper33182dd2012-12-05 14:57:28 +0000109 // Consume leading line comments, e.g. for branches without compounds.
110 while (FormatTok.Tok.is(tok::comment)) {
111 nextToken();
112 addUnwrappedLine();
113 }
114
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000115 switch (FormatTok.Tok.getKind()) {
116 case tok::kw_public:
117 case tok::kw_protected:
118 case tok::kw_private:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000119 parseAccessSpecifier();
120 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000121 case tok::kw_if:
122 parseIfThenElse();
Daniel Jasperbac016b2012-12-03 18:12:45 +0000123 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000124 case tok::kw_do:
125 parseDoWhile();
126 return;
127 case tok::kw_switch:
128 parseSwitch();
129 return;
130 case tok::kw_default:
131 nextToken();
132 parseLabel();
133 return;
134 case tok::kw_case:
135 parseCaseLabel();
136 return;
137 default:
138 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000139 }
140 int TokenNumber = 0;
141 do {
142 ++TokenNumber;
143 switch (FormatTok.Tok.getKind()) {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000144 case tok::kw_enum:
145 parseEnum();
146 return;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000147 case tok::semi:
148 nextToken();
149 addUnwrappedLine();
150 return;
151 case tok::l_paren:
152 parseParens();
153 break;
154 case tok::l_brace:
155 parseBlock();
156 addUnwrappedLine();
157 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000158 case tok::identifier:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000159 nextToken();
160 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
161 parseLabel();
162 return;
163 }
164 break;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000165 default:
166 nextToken();
167 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000168 }
169 } while (!eof());
170}
171
172void UnwrappedLineParser::parseParens() {
173 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
174 nextToken();
175 do {
176 switch (FormatTok.Tok.getKind()) {
177 case tok::l_paren:
178 parseParens();
179 break;
180 case tok::r_paren:
181 nextToken();
182 return;
183 default:
184 nextToken();
185 break;
186 }
187 } while (!eof());
188}
189
190void UnwrappedLineParser::parseIfThenElse() {
191 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
192 nextToken();
193 parseParens();
194 bool NeedsUnwrappedLine = false;
195 if (FormatTok.Tok.is(tok::l_brace)) {
196 parseBlock();
197 NeedsUnwrappedLine = true;
198 } else {
199 addUnwrappedLine();
200 ++Line.Level;
201 parseStatement();
202 --Line.Level;
203 }
204 if (FormatTok.Tok.is(tok::kw_else)) {
205 nextToken();
206 if (FormatTok.Tok.is(tok::l_brace)) {
207 parseBlock();
208 addUnwrappedLine();
209 } else if (FormatTok.Tok.is(tok::kw_if)) {
210 parseIfThenElse();
211 } else {
212 addUnwrappedLine();
213 ++Line.Level;
214 parseStatement();
215 --Line.Level;
216 }
217 } else if (NeedsUnwrappedLine) {
218 addUnwrappedLine();
219 }
220}
221
222void UnwrappedLineParser::parseDoWhile() {
223 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
224 nextToken();
225 if (FormatTok.Tok.is(tok::l_brace)) {
226 parseBlock();
227 } else {
228 addUnwrappedLine();
229 ++Line.Level;
230 parseStatement();
231 --Line.Level;
232 }
233
Alexander Kornienko393b0082012-12-04 15:40:36 +0000234 // FIXME: Add error handling.
235 if (!FormatTok.Tok.is(tok::kw_while)) {
236 addUnwrappedLine();
237 return;
238 }
239
Daniel Jasperbac016b2012-12-03 18:12:45 +0000240 nextToken();
241 parseStatement();
242}
243
244void UnwrappedLineParser::parseLabel() {
245 // FIXME: remove all asserts.
246 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
247 nextToken();
248 unsigned OldLineLevel = Line.Level;
249 if (Line.Level > 0)
250 --Line.Level;
251 if (FormatTok.Tok.is(tok::l_brace)) {
252 parseBlock();
253 }
254 addUnwrappedLine();
255 Line.Level = OldLineLevel;
256}
257
258void UnwrappedLineParser::parseCaseLabel() {
259 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
260 // FIXME: fix handling of complex expressions here.
261 do {
262 nextToken();
263 } while (!eof() && !FormatTok.Tok.is(tok::colon));
264 parseLabel();
265}
266
267void UnwrappedLineParser::parseSwitch() {
268 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
269 nextToken();
270 parseParens();
271 if (FormatTok.Tok.is(tok::l_brace)) {
272 parseBlock();
273 addUnwrappedLine();
274 } else {
275 addUnwrappedLine();
276 ++Line.Level;
277 parseStatement();
278 --Line.Level;
279 }
280}
281
282void UnwrappedLineParser::parseAccessSpecifier() {
283 nextToken();
284 nextToken();
285 addUnwrappedLine();
286}
287
288void UnwrappedLineParser::parseEnum() {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000289 bool HasContents = false;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000290 do {
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000291 switch (FormatTok.Tok.getKind()) {
292 case tok::l_brace:
293 nextToken();
294 addUnwrappedLine();
295 ++Line.Level;
296 break;
297 case tok::l_paren:
298 parseParens();
299 break;
300 case tok::comma:
301 nextToken();
302 addUnwrappedLine();
303 break;
304 case tok::r_brace:
305 if (HasContents)
306 addUnwrappedLine();
307 --Line.Level;
308 nextToken();
309 break;
310 case tok::semi:
Daniel Jasperbac016b2012-12-03 18:12:45 +0000311 nextToken();
312 addUnwrappedLine();
313 return;
Alexander Kornienkoa166e732012-12-04 14:46:19 +0000314 default:
315 HasContents = true;
316 nextToken();
317 break;
Daniel Jasperbac016b2012-12-03 18:12:45 +0000318 }
319 } while (!eof());
320}
321
322void UnwrappedLineParser::addUnwrappedLine() {
323 // Consume trailing comments.
324 while (!eof() && FormatTok.NewlinesBefore == 0 &&
325 FormatTok.Tok.is(tok::comment)) {
326 nextToken();
327 }
Alexander Kornienko720ffb62012-12-05 13:56:52 +0000328 Callback.consumeUnwrappedLine(Line);
Daniel Jasperbac016b2012-12-03 18:12:45 +0000329 Line.Tokens.clear();
330}
331
332bool UnwrappedLineParser::eof() const {
333 return FormatTok.Tok.is(tok::eof);
334}
335
336void UnwrappedLineParser::nextToken() {
337 if (eof())
338 return;
339 Line.Tokens.push_back(FormatTok);
340 parseToken();
341}
342
343void UnwrappedLineParser::parseToken() {
344 if (GreaterStashed) {
345 FormatTok.NewlinesBefore = 0;
346 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
347 FormatTok.WhiteSpaceLength = 0;
348 GreaterStashed = false;
349 return;
350 }
351
352 FormatTok = FormatToken();
353 Lex.LexFromRawLexer(FormatTok.Tok);
354 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
355
356 // Consume and record whitespace until we find a significant token.
357 while (FormatTok.Tok.is(tok::unknown)) {
358 FormatTok.NewlinesBefore += tokenText().count('\n');
359 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
360
361 if (eof())
362 return;
363 Lex.LexFromRawLexer(FormatTok.Tok);
364 }
365
366 if (FormatTok.Tok.is(tok::raw_identifier)) {
367 const IdentifierInfo &Info = IdentTable.get(tokenText());
368 FormatTok.Tok.setKind(Info.getTokenID());
369 }
370
371 if (FormatTok.Tok.is(tok::greatergreater)) {
372 FormatTok.Tok.setKind(tok::greater);
373 GreaterStashed = true;
374 }
375}
376
377StringRef UnwrappedLineParser::tokenText() {
378 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
379 FormatTok.Tok.getLength());
380 return Data;
381}
382
383} // end namespace format
384} // end namespace clang