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