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 #include "llvm/Support/raw_ostream.h"
21 
22 namespace clang {
23 namespace format {
24 
25 UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
26                                          FormatTokenSource &Tokens,
27                                          UnwrappedLineConsumer &Callback)
28     : Style(Style), Tokens(Tokens), Callback(Callback) {
29 }
30 
31 bool UnwrappedLineParser::parse() {
32   FormatTok = Tokens.getNextToken();
33   return parseLevel();
34 }
35 
36 bool UnwrappedLineParser::parseLevel() {
37   bool Error = false;
38   do {
39     switch (FormatTok.Tok.getKind()) {
40     case tok::hash:
41       parsePPDirective();
42       break;
43     case tok::comment:
44       nextToken();
45       addUnwrappedLine();
46       break;
47     case tok::l_brace:
48       Error |= parseBlock();
49       addUnwrappedLine();
50       break;
51     case tok::r_brace:
52       // Stray '}' is an error.
53       return true;
54     default:
55       parseStatement();
56       break;
57     }
58   } while (!eof());
59   return Error;
60 }
61 
62 bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
63   assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
64   nextToken();
65 
66   addUnwrappedLine();
67 
68   Line.Level += AddLevels;
69   parseLevel();
70   Line.Level -= AddLevels;
71 
72   // FIXME: Add error handling.
73   if (!FormatTok.Tok.is(tok::r_brace))
74     return true;
75 
76   nextToken();
77   if (FormatTok.Tok.is(tok::semi))
78     nextToken();
79   return false;
80 }
81 
82 void UnwrappedLineParser::parsePPDirective() {
83   assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
84   nextToken();
85 
86   Line.InPPDirective = true;
87   if (FormatTok.Tok.getIdentifierInfo() == NULL) {
88     addUnwrappedLine();
89     Line.InPPDirective = false;
90     return;
91   }
92 
93   do {
94     if (FormatTok.NewlinesBefore > 0 &&
95         FormatTok.HasUnescapedNewline) {
96       break;
97     }
98     nextToken();
99   } while (!eof());
100   addUnwrappedLine();
101   Line.InPPDirective = false;
102 }
103 
104 void UnwrappedLineParser::parseComments() {
105   // Consume leading line comments, e.g. for branches without compounds.
106   while (FormatTok.Tok.is(tok::comment)) {
107     nextToken();
108     addUnwrappedLine();
109   }
110 }
111 
112 void UnwrappedLineParser::parseStatement() {
113   parseComments();
114 
115   int TokenNumber = 0;
116   switch (FormatTok.Tok.getKind()) {
117   case tok::kw_namespace:
118     parseNamespace();
119     return;
120   case tok::kw_inline:
121     nextToken();
122     TokenNumber++;
123     if (FormatTok.Tok.is(tok::kw_namespace)) {
124       parseNamespace();
125       return;
126     }
127     break;
128   case tok::kw_public:
129   case tok::kw_protected:
130   case tok::kw_private:
131     parseAccessSpecifier();
132     return;
133   case tok::kw_if:
134     parseIfThenElse();
135     return;
136   case tok::kw_for:
137   case tok::kw_while:
138     parseForOrWhileLoop();
139     return;
140   case tok::kw_do:
141     parseDoWhile();
142     return;
143   case tok::kw_switch:
144     parseSwitch();
145     return;
146   case tok::kw_default:
147     nextToken();
148     parseLabel();
149     return;
150   case tok::kw_case:
151     parseCaseLabel();
152     return;
153   default:
154     break;
155   }
156   do {
157     ++TokenNumber;
158     switch (FormatTok.Tok.getKind()) {
159     case tok::kw_enum:
160       parseEnum();
161       return;
162     case tok::semi:
163       nextToken();
164       addUnwrappedLine();
165       return;
166     case tok::l_paren:
167       parseParens();
168       break;
169     case tok::l_brace:
170       parseBlock();
171       addUnwrappedLine();
172       return;
173     case tok::identifier:
174       nextToken();
175       if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
176         parseLabel();
177         return;
178       }
179       break;
180     case tok::equal:
181       nextToken();
182       // Skip initializers as they will be formatted by a later step.
183       if (FormatTok.Tok.is(tok::l_brace))
184         nextToken();
185       break;
186     default:
187       nextToken();
188       break;
189     }
190   } while (!eof());
191 }
192 
193 void UnwrappedLineParser::parseParens() {
194   assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
195   nextToken();
196   do {
197     switch (FormatTok.Tok.getKind()) {
198     case tok::l_paren:
199       parseParens();
200       break;
201     case tok::r_paren:
202       nextToken();
203       return;
204     default:
205       nextToken();
206       break;
207     }
208   } while (!eof());
209 }
210 
211 void UnwrappedLineParser::parseIfThenElse() {
212   assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
213   nextToken();
214   parseParens();
215   bool NeedsUnwrappedLine = false;
216   if (FormatTok.Tok.is(tok::l_brace)) {
217     parseBlock();
218     NeedsUnwrappedLine = true;
219   } else {
220     addUnwrappedLine();
221     ++Line.Level;
222     parseStatement();
223     --Line.Level;
224   }
225   if (FormatTok.Tok.is(tok::kw_else)) {
226     nextToken();
227     if (FormatTok.Tok.is(tok::l_brace)) {
228       parseBlock();
229       addUnwrappedLine();
230     } else if (FormatTok.Tok.is(tok::kw_if)) {
231       parseIfThenElse();
232     } else {
233       addUnwrappedLine();
234       ++Line.Level;
235       parseStatement();
236       --Line.Level;
237     }
238   } else if (NeedsUnwrappedLine) {
239     addUnwrappedLine();
240   }
241 }
242 
243 void UnwrappedLineParser::parseNamespace() {
244   assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
245   nextToken();
246   if (FormatTok.Tok.is(tok::identifier))
247     nextToken();
248   if (FormatTok.Tok.is(tok::l_brace)) {
249     parseBlock(0);
250     addUnwrappedLine();
251   }
252   // FIXME: Add error handling.
253 }
254 
255 void UnwrappedLineParser::parseForOrWhileLoop() {
256   assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
257          "'for' or 'while' expected");
258   nextToken();
259   parseParens();
260   if (FormatTok.Tok.is(tok::l_brace)) {
261     parseBlock();
262     addUnwrappedLine();
263   } else {
264     addUnwrappedLine();
265     ++Line.Level;
266     parseStatement();
267     --Line.Level;
268   }
269 }
270 
271 void UnwrappedLineParser::parseDoWhile() {
272   assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
273   nextToken();
274   if (FormatTok.Tok.is(tok::l_brace)) {
275     parseBlock();
276   } else {
277     addUnwrappedLine();
278     ++Line.Level;
279     parseStatement();
280     --Line.Level;
281   }
282 
283   // FIXME: Add error handling.
284   if (!FormatTok.Tok.is(tok::kw_while)) {
285     addUnwrappedLine();
286     return;
287   }
288 
289   nextToken();
290   parseStatement();
291 }
292 
293 void UnwrappedLineParser::parseLabel() {
294   // FIXME: remove all asserts.
295   assert(FormatTok.Tok.is(tok::colon) && "':' expected");
296   nextToken();
297   unsigned OldLineLevel = Line.Level;
298   if (Line.Level > 0)
299     --Line.Level;
300   if (FormatTok.Tok.is(tok::l_brace)) {
301     parseBlock();
302   }
303   addUnwrappedLine();
304   Line.Level = OldLineLevel;
305 }
306 
307 void UnwrappedLineParser::parseCaseLabel() {
308   assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
309   // FIXME: fix handling of complex expressions here.
310   do {
311     nextToken();
312   } while (!eof() && !FormatTok.Tok.is(tok::colon));
313   parseLabel();
314 }
315 
316 void UnwrappedLineParser::parseSwitch() {
317   assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
318   nextToken();
319   parseParens();
320   if (FormatTok.Tok.is(tok::l_brace)) {
321     parseBlock(Style.IndentCaseLabels ? 2 : 1);
322     addUnwrappedLine();
323   } else {
324     addUnwrappedLine();
325     Line.Level += (Style.IndentCaseLabels ? 2 : 1);
326     parseStatement();
327     Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
328   }
329 }
330 
331 void UnwrappedLineParser::parseAccessSpecifier() {
332   nextToken();
333   // Otherwise, we don't know what it is, and we'd better keep the next token.
334   if (FormatTok.Tok.is(tok::colon))
335     nextToken();
336   addUnwrappedLine();
337 }
338 
339 void UnwrappedLineParser::parseEnum() {
340   bool HasContents = false;
341   do {
342     switch (FormatTok.Tok.getKind()) {
343     case tok::l_brace:
344       nextToken();
345       addUnwrappedLine();
346       ++Line.Level;
347       parseComments();
348       break;
349     case tok::l_paren:
350       parseParens();
351       break;
352     case tok::comma:
353       nextToken();
354       addUnwrappedLine();
355       parseComments();
356       break;
357     case tok::r_brace:
358       if (HasContents)
359         addUnwrappedLine();
360       --Line.Level;
361       nextToken();
362       break;
363     case tok::semi:
364       nextToken();
365       addUnwrappedLine();
366       return;
367     default:
368       HasContents = true;
369       nextToken();
370       break;
371     }
372   } while (!eof());
373 }
374 
375 void UnwrappedLineParser::addUnwrappedLine() {
376   // Consume trailing comments.
377   while (!eof() && FormatTok.NewlinesBefore == 0 &&
378          FormatTok.Tok.is(tok::comment)) {
379     nextToken();
380   }
381   Callback.consumeUnwrappedLine(Line);
382   Line.Tokens.clear();
383 }
384 
385 bool UnwrappedLineParser::eof() const {
386   return FormatTok.Tok.is(tok::eof);
387 }
388 
389 void UnwrappedLineParser::nextToken() {
390   if (eof())
391     return;
392   Line.Tokens.push_back(FormatTok);
393   FormatTok = Tokens.getNextToken();
394 }
395 
396 }  // end namespace format
397 }  // end namespace clang
398