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