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