blob: d9ff99d3cb866ea1e35210d3563b6a39f7011363 [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() {
102 if (FormatTok.Tok.is(tok::kw_public) || FormatTok.Tok.is(tok::kw_protected) ||
103 FormatTok.Tok.is(tok::kw_private)) {
104 parseAccessSpecifier();
105 return;
106 }
107 if (FormatTok.Tok.is(tok::kw_enum)) {
108 parseEnum();
109 return;
110 }
111 int TokenNumber = 0;
112 do {
113 ++TokenNumber;
114 switch (FormatTok.Tok.getKind()) {
115 case tok::semi:
116 nextToken();
117 addUnwrappedLine();
118 return;
119 case tok::l_paren:
120 parseParens();
121 break;
122 case tok::l_brace:
123 parseBlock();
124 addUnwrappedLine();
125 return;
126 case tok::kw_if:
127 parseIfThenElse();
128 return;
129 case tok::kw_do:
130 parseDoWhile();
131 return;
132 case tok::kw_switch:
133 parseSwitch();
134 return;
135 case tok::kw_default:
136 nextToken();
137 parseLabel();
138 return;
139 case tok::kw_case:
140 parseCaseLabel();
141 return;
142 case tok::raw_identifier:
143 nextToken();
144 break;
145 default:
146 nextToken();
147 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
148 parseLabel();
149 return;
150 }
151 break;
152 }
153 } while (!eof());
154}
155
156void UnwrappedLineParser::parseParens() {
157 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
158 nextToken();
159 do {
160 switch (FormatTok.Tok.getKind()) {
161 case tok::l_paren:
162 parseParens();
163 break;
164 case tok::r_paren:
165 nextToken();
166 return;
167 default:
168 nextToken();
169 break;
170 }
171 } while (!eof());
172}
173
174void UnwrappedLineParser::parseIfThenElse() {
175 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
176 nextToken();
177 parseParens();
178 bool NeedsUnwrappedLine = false;
179 if (FormatTok.Tok.is(tok::l_brace)) {
180 parseBlock();
181 NeedsUnwrappedLine = true;
182 } else {
183 addUnwrappedLine();
184 ++Line.Level;
185 parseStatement();
186 --Line.Level;
187 }
188 if (FormatTok.Tok.is(tok::kw_else)) {
189 nextToken();
190 if (FormatTok.Tok.is(tok::l_brace)) {
191 parseBlock();
192 addUnwrappedLine();
193 } else if (FormatTok.Tok.is(tok::kw_if)) {
194 parseIfThenElse();
195 } else {
196 addUnwrappedLine();
197 ++Line.Level;
198 parseStatement();
199 --Line.Level;
200 }
201 } else if (NeedsUnwrappedLine) {
202 addUnwrappedLine();
203 }
204}
205
206void UnwrappedLineParser::parseDoWhile() {
207 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
208 nextToken();
209 if (FormatTok.Tok.is(tok::l_brace)) {
210 parseBlock();
211 } else {
212 addUnwrappedLine();
213 ++Line.Level;
214 parseStatement();
215 --Line.Level;
216 }
217
218 assert(FormatTok.Tok.is(tok::kw_while) && "'while' expected");
219 nextToken();
220 parseStatement();
221}
222
223void UnwrappedLineParser::parseLabel() {
224 // FIXME: remove all asserts.
225 assert(FormatTok.Tok.is(tok::colon) && "':' expected");
226 nextToken();
227 unsigned OldLineLevel = Line.Level;
228 if (Line.Level > 0)
229 --Line.Level;
230 if (FormatTok.Tok.is(tok::l_brace)) {
231 parseBlock();
232 }
233 addUnwrappedLine();
234 Line.Level = OldLineLevel;
235}
236
237void UnwrappedLineParser::parseCaseLabel() {
238 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
239 // FIXME: fix handling of complex expressions here.
240 do {
241 nextToken();
242 } while (!eof() && !FormatTok.Tok.is(tok::colon));
243 parseLabel();
244}
245
246void UnwrappedLineParser::parseSwitch() {
247 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
248 nextToken();
249 parseParens();
250 if (FormatTok.Tok.is(tok::l_brace)) {
251 parseBlock();
252 addUnwrappedLine();
253 } else {
254 addUnwrappedLine();
255 ++Line.Level;
256 parseStatement();
257 --Line.Level;
258 }
259}
260
261void UnwrappedLineParser::parseAccessSpecifier() {
262 nextToken();
263 nextToken();
264 addUnwrappedLine();
265}
266
267void UnwrappedLineParser::parseEnum() {
268 do {
269 nextToken();
270 if (FormatTok.Tok.is(tok::semi)) {
271 nextToken();
272 addUnwrappedLine();
273 return;
274 }
275 } while (!eof());
276}
277
278void UnwrappedLineParser::addUnwrappedLine() {
279 // Consume trailing comments.
280 while (!eof() && FormatTok.NewlinesBefore == 0 &&
281 FormatTok.Tok.is(tok::comment)) {
282 nextToken();
283 }
284 Callback.formatUnwrappedLine(Line);
285 Line.Tokens.clear();
286}
287
288bool UnwrappedLineParser::eof() const {
289 return FormatTok.Tok.is(tok::eof);
290}
291
292void UnwrappedLineParser::nextToken() {
293 if (eof())
294 return;
295 Line.Tokens.push_back(FormatTok);
296 parseToken();
297}
298
299void UnwrappedLineParser::parseToken() {
300 if (GreaterStashed) {
301 FormatTok.NewlinesBefore = 0;
302 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
303 FormatTok.WhiteSpaceLength = 0;
304 GreaterStashed = false;
305 return;
306 }
307
308 FormatTok = FormatToken();
309 Lex.LexFromRawLexer(FormatTok.Tok);
310 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
311
312 // Consume and record whitespace until we find a significant token.
313 while (FormatTok.Tok.is(tok::unknown)) {
314 FormatTok.NewlinesBefore += tokenText().count('\n');
315 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
316
317 if (eof())
318 return;
319 Lex.LexFromRawLexer(FormatTok.Tok);
320 }
321
322 if (FormatTok.Tok.is(tok::raw_identifier)) {
323 const IdentifierInfo &Info = IdentTable.get(tokenText());
324 FormatTok.Tok.setKind(Info.getTokenID());
325 }
326
327 if (FormatTok.Tok.is(tok::greatergreater)) {
328 FormatTok.Tok.setKind(tok::greater);
329 GreaterStashed = true;
330 }
331}
332
333StringRef UnwrappedLineParser::tokenText() {
334 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
335 FormatTok.Tok.getLength());
336 return Data;
337}
338
339} // end namespace format
340} // end namespace clang