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