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