1 //===--- 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"
20 
21 #include "llvm/Support/raw_ostream.h"
22 
23 namespace clang {
24 namespace format {
25 
26 UnwrappedLineParser::UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr,
27                                          UnwrappedLineConsumer &Callback)
28     : GreaterStashed(false),
29       Lex(Lex),
30       SourceMgr(SourceMgr),
31       IdentTable(Lex.getLangOpts()),
32       Callback(Callback) {
33   Lex.SetKeepWhitespaceMode(true);
34 }
35 
36 void UnwrappedLineParser::parse() {
37   parseToken();
38   parseLevel();
39 }
40 
41 void UnwrappedLineParser::parseLevel() {
42   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:
51       parseBlock();
52       addUnwrappedLine();
53       break;
54     case tok::r_brace:
55       return;
56     default:
57       parseStatement();
58       break;
59     }
60   } while (!eof());
61 }
62 
63 void UnwrappedLineParser::parseBlock() {
64   nextToken();
65 
66   // FIXME: Remove this hack to handle namespaces.
67   bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace);
68 
69   addUnwrappedLine();
70 
71   if (!IsNamespace)
72     ++Line.Level;
73   parseLevel();
74   if (!IsNamespace)
75     --Line.Level;
76   assert(FormatTok.Tok.is(tok::r_brace) && "expected '}'");
77   nextToken();
78   if (FormatTok.Tok.is(tok::semi))
79     nextToken();
80 }
81 
82 void UnwrappedLineParser::parsePPDirective() {
83   while (!eof()) {
84     nextToken();
85     if (FormatTok.NewlinesBefore > 0) {
86       addUnwrappedLine();
87       return;
88     }
89   }
90 }
91 
92 void UnwrappedLineParser::parseComment() {
93   while (!eof()) {
94     nextToken();
95     if (FormatTok.NewlinesBefore > 0) {
96       addUnwrappedLine();
97       return;
98     }
99   }
100 }
101 
102 void UnwrappedLineParser::parseStatement() {
103   if (FormatTok.Tok.is(tok::kw_public) || FormatTok.Tok.is(tok::kw_protected) ||
104       FormatTok.Tok.is(tok::kw_private)) {
105     parseAccessSpecifier();
106     return;
107   }
108   if (FormatTok.Tok.is(tok::kw_enum)) {
109     parseEnum();
110     return;
111   }
112   int TokenNumber = 0;
113   do {
114     ++TokenNumber;
115     switch (FormatTok.Tok.getKind()) {
116     case tok::semi:
117       nextToken();
118       addUnwrappedLine();
119       return;
120     case tok::l_paren:
121       parseParens();
122       break;
123     case tok::l_brace:
124       parseBlock();
125       addUnwrappedLine();
126       return;
127     case tok::kw_if:
128       parseIfThenElse();
129       return;
130     case tok::kw_do:
131       parseDoWhile();
132       return;
133     case tok::kw_switch:
134       parseSwitch();
135       return;
136     case tok::kw_default:
137       nextToken();
138       parseLabel();
139       return;
140     case tok::kw_case:
141       parseCaseLabel();
142       return;
143     case tok::raw_identifier:
144       nextToken();
145       break;
146     default:
147       nextToken();
148       if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
149         parseLabel();
150         return;
151       }
152       break;
153     }
154   } while (!eof());
155 }
156 
157 void UnwrappedLineParser::parseParens() {
158   assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
159   nextToken();
160   do {
161     switch (FormatTok.Tok.getKind()) {
162     case tok::l_paren:
163       parseParens();
164       break;
165     case tok::r_paren:
166       nextToken();
167       return;
168     default:
169       nextToken();
170       break;
171     }
172   } while (!eof());
173 }
174 
175 void UnwrappedLineParser::parseIfThenElse() {
176   assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
177   nextToken();
178   parseParens();
179   bool NeedsUnwrappedLine = false;
180   if (FormatTok.Tok.is(tok::l_brace)) {
181     parseBlock();
182     NeedsUnwrappedLine = true;
183   } else {
184     addUnwrappedLine();
185     ++Line.Level;
186     parseStatement();
187     --Line.Level;
188   }
189   if (FormatTok.Tok.is(tok::kw_else)) {
190     nextToken();
191     if (FormatTok.Tok.is(tok::l_brace)) {
192       parseBlock();
193       addUnwrappedLine();
194     } else if (FormatTok.Tok.is(tok::kw_if)) {
195       parseIfThenElse();
196     } else {
197       addUnwrappedLine();
198       ++Line.Level;
199       parseStatement();
200       --Line.Level;
201     }
202   } else if (NeedsUnwrappedLine) {
203     addUnwrappedLine();
204   }
205 }
206 
207 void UnwrappedLineParser::parseDoWhile() {
208   assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
209   nextToken();
210   if (FormatTok.Tok.is(tok::l_brace)) {
211     parseBlock();
212   } else {
213     addUnwrappedLine();
214     ++Line.Level;
215     parseStatement();
216     --Line.Level;
217   }
218 
219   assert(FormatTok.Tok.is(tok::kw_while) && "'while' expected");
220   nextToken();
221   parseStatement();
222 }
223 
224 void UnwrappedLineParser::parseLabel() {
225   // FIXME: remove all asserts.
226   assert(FormatTok.Tok.is(tok::colon) && "':' expected");
227   nextToken();
228   unsigned OldLineLevel = Line.Level;
229   if (Line.Level > 0)
230     --Line.Level;
231   if (FormatTok.Tok.is(tok::l_brace)) {
232     parseBlock();
233   }
234   addUnwrappedLine();
235   Line.Level = OldLineLevel;
236 }
237 
238 void UnwrappedLineParser::parseCaseLabel() {
239   assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
240   // FIXME: fix handling of complex expressions here.
241   do {
242     nextToken();
243   } while (!eof() && !FormatTok.Tok.is(tok::colon));
244   parseLabel();
245 }
246 
247 void UnwrappedLineParser::parseSwitch() {
248   assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
249   nextToken();
250   parseParens();
251   if (FormatTok.Tok.is(tok::l_brace)) {
252     parseBlock();
253     addUnwrappedLine();
254   } else {
255     addUnwrappedLine();
256     ++Line.Level;
257     parseStatement();
258     --Line.Level;
259   }
260 }
261 
262 void UnwrappedLineParser::parseAccessSpecifier() {
263   nextToken();
264   nextToken();
265   addUnwrappedLine();
266 }
267 
268 void UnwrappedLineParser::parseEnum() {
269   do {
270     nextToken();
271     if (FormatTok.Tok.is(tok::semi)) {
272       nextToken();
273       addUnwrappedLine();
274       return;
275     }
276   } while (!eof());
277 }
278 
279 void UnwrappedLineParser::addUnwrappedLine() {
280   // Consume trailing comments.
281   while (!eof() && FormatTok.NewlinesBefore == 0 &&
282          FormatTok.Tok.is(tok::comment)) {
283     nextToken();
284   }
285   Callback.formatUnwrappedLine(Line);
286   Line.Tokens.clear();
287 }
288 
289 bool UnwrappedLineParser::eof() const {
290   return FormatTok.Tok.is(tok::eof);
291 }
292 
293 void UnwrappedLineParser::nextToken() {
294   if (eof())
295     return;
296   Line.Tokens.push_back(FormatTok);
297   parseToken();
298 }
299 
300 void UnwrappedLineParser::parseToken() {
301   if (GreaterStashed) {
302     FormatTok.NewlinesBefore = 0;
303     FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1);
304     FormatTok.WhiteSpaceLength = 0;
305     GreaterStashed = false;
306     return;
307   }
308 
309   FormatTok = FormatToken();
310   Lex.LexFromRawLexer(FormatTok.Tok);
311   FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
312 
313   // Consume and record whitespace until we find a significant token.
314   while (FormatTok.Tok.is(tok::unknown)) {
315     FormatTok.NewlinesBefore += tokenText().count('\n');
316     FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
317 
318     if (eof())
319       return;
320     Lex.LexFromRawLexer(FormatTok.Tok);
321   }
322 
323   if (FormatTok.Tok.is(tok::raw_identifier)) {
324     const IdentifierInfo &Info = IdentTable.get(tokenText());
325     FormatTok.Tok.setKind(Info.getTokenID());
326   }
327 
328   if (FormatTok.Tok.is(tok::greatergreater)) {
329     FormatTok.Tok.setKind(tok::greater);
330     GreaterStashed = true;
331   }
332 }
333 
334 StringRef UnwrappedLineParser::tokenText() {
335   StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()),
336                  FormatTok.Tok.getLength());
337   return Data;
338 }
339 
340 }  // end namespace format
341 }  // end namespace clang
342