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 21 #include "llvm/Support/raw_ostream.h" 22 23 namespace clang { 24 namespace format { 25 26 UnwrappedLineParser::UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr, 27 UnwrappedLineConsumer &Callback) 28 : GreaterStashed(false), 29 Lex(Lex), 30 SourceMgr(SourceMgr), 31 IdentTable(Lex.getLangOpts()), 32 Callback(Callback) { 33 Lex.SetKeepWhitespaceMode(true); 34 } 35 36 void UnwrappedLineParser::parse() { 37 parseToken(); 38 parseLevel(); 39 } 40 41 void UnwrappedLineParser::parseLevel() { 42 do { 43 switch (FormatTok.Tok.getKind()) { 44 case tok::hash: 45 parsePPDirective(); 46 break; 47 case tok::comment: 48 parseComment(); 49 break; 50 case tok::l_brace: 51 parseBlock(); 52 addUnwrappedLine(); 53 break; 54 case tok::r_brace: 55 return; 56 default: 57 parseStatement(); 58 break; 59 } 60 } while (!eof()); 61 } 62 63 void UnwrappedLineParser::parseBlock() { 64 nextToken(); 65 66 // FIXME: Remove this hack to handle namespaces. 67 bool IsNamespace = Line.Tokens[0].Tok.is(tok::kw_namespace); 68 69 addUnwrappedLine(); 70 71 if (!IsNamespace) 72 ++Line.Level; 73 parseLevel(); 74 if (!IsNamespace) 75 --Line.Level; 76 assert(FormatTok.Tok.is(tok::r_brace) && "expected '}'"); 77 nextToken(); 78 if (FormatTok.Tok.is(tok::semi)) 79 nextToken(); 80 } 81 82 void UnwrappedLineParser::parsePPDirective() { 83 while (!eof()) { 84 nextToken(); 85 if (FormatTok.NewlinesBefore > 0) { 86 addUnwrappedLine(); 87 return; 88 } 89 } 90 } 91 92 void UnwrappedLineParser::parseComment() { 93 while (!eof()) { 94 nextToken(); 95 if (FormatTok.NewlinesBefore > 0) { 96 addUnwrappedLine(); 97 return; 98 } 99 } 100 } 101 102 void UnwrappedLineParser::parseStatement() { 103 if (FormatTok.Tok.is(tok::kw_public) || FormatTok.Tok.is(tok::kw_protected) || 104 FormatTok.Tok.is(tok::kw_private)) { 105 parseAccessSpecifier(); 106 return; 107 } 108 if (FormatTok.Tok.is(tok::kw_enum)) { 109 parseEnum(); 110 return; 111 } 112 int TokenNumber = 0; 113 do { 114 ++TokenNumber; 115 switch (FormatTok.Tok.getKind()) { 116 case tok::semi: 117 nextToken(); 118 addUnwrappedLine(); 119 return; 120 case tok::l_paren: 121 parseParens(); 122 break; 123 case tok::l_brace: 124 parseBlock(); 125 addUnwrappedLine(); 126 return; 127 case tok::kw_if: 128 parseIfThenElse(); 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 case tok::raw_identifier: 144 nextToken(); 145 break; 146 default: 147 nextToken(); 148 if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) { 149 parseLabel(); 150 return; 151 } 152 break; 153 } 154 } while (!eof()); 155 } 156 157 void UnwrappedLineParser::parseParens() { 158 assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected."); 159 nextToken(); 160 do { 161 switch (FormatTok.Tok.getKind()) { 162 case tok::l_paren: 163 parseParens(); 164 break; 165 case tok::r_paren: 166 nextToken(); 167 return; 168 default: 169 nextToken(); 170 break; 171 } 172 } while (!eof()); 173 } 174 175 void UnwrappedLineParser::parseIfThenElse() { 176 assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected"); 177 nextToken(); 178 parseParens(); 179 bool NeedsUnwrappedLine = false; 180 if (FormatTok.Tok.is(tok::l_brace)) { 181 parseBlock(); 182 NeedsUnwrappedLine = true; 183 } else { 184 addUnwrappedLine(); 185 ++Line.Level; 186 parseStatement(); 187 --Line.Level; 188 } 189 if (FormatTok.Tok.is(tok::kw_else)) { 190 nextToken(); 191 if (FormatTok.Tok.is(tok::l_brace)) { 192 parseBlock(); 193 addUnwrappedLine(); 194 } else if (FormatTok.Tok.is(tok::kw_if)) { 195 parseIfThenElse(); 196 } else { 197 addUnwrappedLine(); 198 ++Line.Level; 199 parseStatement(); 200 --Line.Level; 201 } 202 } else if (NeedsUnwrappedLine) { 203 addUnwrappedLine(); 204 } 205 } 206 207 void UnwrappedLineParser::parseDoWhile() { 208 assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected"); 209 nextToken(); 210 if (FormatTok.Tok.is(tok::l_brace)) { 211 parseBlock(); 212 } else { 213 addUnwrappedLine(); 214 ++Line.Level; 215 parseStatement(); 216 --Line.Level; 217 } 218 219 assert(FormatTok.Tok.is(tok::kw_while) && "'while' expected"); 220 nextToken(); 221 parseStatement(); 222 } 223 224 void UnwrappedLineParser::parseLabel() { 225 // FIXME: remove all asserts. 226 assert(FormatTok.Tok.is(tok::colon) && "':' expected"); 227 nextToken(); 228 unsigned OldLineLevel = Line.Level; 229 if (Line.Level > 0) 230 --Line.Level; 231 if (FormatTok.Tok.is(tok::l_brace)) { 232 parseBlock(); 233 } 234 addUnwrappedLine(); 235 Line.Level = OldLineLevel; 236 } 237 238 void UnwrappedLineParser::parseCaseLabel() { 239 assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected"); 240 // FIXME: fix handling of complex expressions here. 241 do { 242 nextToken(); 243 } while (!eof() && !FormatTok.Tok.is(tok::colon)); 244 parseLabel(); 245 } 246 247 void UnwrappedLineParser::parseSwitch() { 248 assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected"); 249 nextToken(); 250 parseParens(); 251 if (FormatTok.Tok.is(tok::l_brace)) { 252 parseBlock(); 253 addUnwrappedLine(); 254 } else { 255 addUnwrappedLine(); 256 ++Line.Level; 257 parseStatement(); 258 --Line.Level; 259 } 260 } 261 262 void UnwrappedLineParser::parseAccessSpecifier() { 263 nextToken(); 264 nextToken(); 265 addUnwrappedLine(); 266 } 267 268 void UnwrappedLineParser::parseEnum() { 269 do { 270 nextToken(); 271 if (FormatTok.Tok.is(tok::semi)) { 272 nextToken(); 273 addUnwrappedLine(); 274 return; 275 } 276 } while (!eof()); 277 } 278 279 void UnwrappedLineParser::addUnwrappedLine() { 280 // Consume trailing comments. 281 while (!eof() && FormatTok.NewlinesBefore == 0 && 282 FormatTok.Tok.is(tok::comment)) { 283 nextToken(); 284 } 285 Callback.formatUnwrappedLine(Line); 286 Line.Tokens.clear(); 287 } 288 289 bool UnwrappedLineParser::eof() const { 290 return FormatTok.Tok.is(tok::eof); 291 } 292 293 void UnwrappedLineParser::nextToken() { 294 if (eof()) 295 return; 296 Line.Tokens.push_back(FormatTok); 297 parseToken(); 298 } 299 300 void UnwrappedLineParser::parseToken() { 301 if (GreaterStashed) { 302 FormatTok.NewlinesBefore = 0; 303 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation().getLocWithOffset(1); 304 FormatTok.WhiteSpaceLength = 0; 305 GreaterStashed = false; 306 return; 307 } 308 309 FormatTok = FormatToken(); 310 Lex.LexFromRawLexer(FormatTok.Tok); 311 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation(); 312 313 // Consume and record whitespace until we find a significant token. 314 while (FormatTok.Tok.is(tok::unknown)) { 315 FormatTok.NewlinesBefore += tokenText().count('\n'); 316 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength(); 317 318 if (eof()) 319 return; 320 Lex.LexFromRawLexer(FormatTok.Tok); 321 } 322 323 if (FormatTok.Tok.is(tok::raw_identifier)) { 324 const IdentifierInfo &Info = IdentTable.get(tokenText()); 325 FormatTok.Tok.setKind(Info.getTokenID()); 326 } 327 328 if (FormatTok.Tok.is(tok::greatergreater)) { 329 FormatTok.Tok.setKind(tok::greater); 330 GreaterStashed = true; 331 } 332 } 333 334 StringRef UnwrappedLineParser::tokenText() { 335 StringRef Data(SourceMgr.getCharacterData(FormatTok.Tok.getLocation()), 336 FormatTok.Tok.getLength()); 337 return Data; 338 } 339 340 } // end namespace format 341 } // end namespace clang 342