| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <sstream> | 5 #include <sstream> |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
| 9 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
| 10 #include "tools/gn/commands.h" | 10 #include "tools/gn/commands.h" |
| 11 #include "tools/gn/filesystem_utils.h" | 11 #include "tools/gn/filesystem_utils.h" |
| 12 #include "tools/gn/input_file.h" | 12 #include "tools/gn/input_file.h" |
| 13 #include "tools/gn/line_breaker.h" |
| 13 #include "tools/gn/parser.h" | 14 #include "tools/gn/parser.h" |
| 14 #include "tools/gn/scheduler.h" | 15 #include "tools/gn/scheduler.h" |
| 15 #include "tools/gn/setup.h" | 16 #include "tools/gn/setup.h" |
| 16 #include "tools/gn/source_file.h" | 17 #include "tools/gn/source_file.h" |
| 17 #include "tools/gn/tokenizer.h" | 18 #include "tools/gn/tokenizer.h" |
| 18 | 19 |
| 19 namespace commands { | 20 namespace commands { |
| 20 | 21 |
| 21 const char kSwitchDumpTree[] = "dump-tree"; | 22 const char kSwitchDumpTree[] = "dump-tree"; |
| 22 const char kSwitchInPlace[] = "in-place"; | 23 const char kSwitchInPlace[] = "in-place"; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 46 " --in-place of course.\n" | 47 " --in-place of course.\n" |
| 47 "\n" | 48 "\n" |
| 48 "Examples\n" | 49 "Examples\n" |
| 49 " gn format //some/BUILD.gn\n" | 50 " gn format //some/BUILD.gn\n" |
| 50 " gn format some\\BUILD.gn\n" | 51 " gn format some\\BUILD.gn\n" |
| 51 " gn format /abspath/some/BUILD.gn\n" | 52 " gn format /abspath/some/BUILD.gn\n" |
| 52 " gn format --stdin\n"; | 53 " gn format --stdin\n"; |
| 53 | 54 |
| 54 namespace { | 55 namespace { |
| 55 | 56 |
| 56 const int kIndentSize = 2; | |
| 57 const int kMaximumWidth = 80; | |
| 58 | |
| 59 enum Precedence { | |
| 60 kPrecedenceLowest, | |
| 61 kPrecedenceAssign, | |
| 62 kPrecedenceOr, | |
| 63 kPrecedenceAnd, | |
| 64 kPrecedenceCompare, | |
| 65 kPrecedenceAdd, | |
| 66 kPrecedenceSuffix, | |
| 67 kPrecedenceUnary, | |
| 68 }; | |
| 69 | |
| 70 class Printer { | 57 class Printer { |
| 71 public: | 58 public: |
| 72 Printer(); | 59 Printer(); |
| 73 ~Printer(); | 60 ~Printer(); |
| 74 | 61 |
| 75 void Block(const ParseNode* file); | 62 void Block(const ParseNode* file); |
| 76 | 63 |
| 77 std::string String() const { return output_; } | 64 std::string String() const { return output_; } |
| 78 | 65 |
| 79 private: | 66 private: |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 // |end| holds any trailing comments to be printed just before the closing | 134 // |end| holds any trailing comments to be printed just before the closing |
| 148 // bracket. | 135 // bracket. |
| 149 template <class PARSENODE> // Just for const covariance. | 136 template <class PARSENODE> // Just for const covariance. |
| 150 void Sequence(SequenceStyle style, | 137 void Sequence(SequenceStyle style, |
| 151 const std::vector<PARSENODE*>& list, | 138 const std::vector<PARSENODE*>& list, |
| 152 const ParseNode* end, | 139 const ParseNode* end, |
| 153 bool force_multiline); | 140 bool force_multiline); |
| 154 | 141 |
| 155 void FunctionCall(const FunctionCallNode* func_call); | 142 void FunctionCall(const FunctionCallNode* func_call); |
| 156 | 143 |
| 144 bool IsStartOfStatement(const ParseNode* node); |
| 145 |
| 157 std::string output_; // Output buffer. | 146 std::string output_; // Output buffer. |
| 158 std::vector<Token> comments_; // Pending end-of-line comments. | 147 std::vector<Token> comments_; // Pending end-of-line comments. |
| 159 int margin_; // Left margin (number of spaces). | 148 int margin_; // Left margin (number of spaces). |
| 160 | 149 |
| 161 // Gives the precedence for operators in a BinaryOpNode. | |
| 162 std::map<base::StringPiece, Precedence> precedence_; | |
| 163 | |
| 164 DISALLOW_COPY_AND_ASSIGN(Printer); | 150 DISALLOW_COPY_AND_ASSIGN(Printer); |
| 165 }; | 151 }; |
| 166 | 152 |
| 167 Printer::Printer() : margin_(0) { | 153 Printer::Printer() : margin_(0) { |
| 168 output_.reserve(100 << 10); | 154 output_.reserve(100 << 10); |
| 169 precedence_["="] = kPrecedenceAssign; | |
| 170 precedence_["+="] = kPrecedenceAssign; | |
| 171 precedence_["-="] = kPrecedenceAssign; | |
| 172 precedence_["||"] = kPrecedenceOr; | |
| 173 precedence_["&&"] = kPrecedenceAnd; | |
| 174 precedence_["<"] = kPrecedenceCompare; | |
| 175 precedence_[">"] = kPrecedenceCompare; | |
| 176 precedence_["=="] = kPrecedenceCompare; | |
| 177 precedence_["!="] = kPrecedenceCompare; | |
| 178 precedence_["<="] = kPrecedenceCompare; | |
| 179 precedence_[">="] = kPrecedenceCompare; | |
| 180 precedence_["+"] = kPrecedenceAdd; | |
| 181 precedence_["-"] = kPrecedenceAdd; | |
| 182 precedence_["!"] = kPrecedenceUnary; | |
| 183 } | 155 } |
| 184 | 156 |
| 185 Printer::~Printer() { | 157 Printer::~Printer() { |
| 186 } | 158 } |
| 187 | 159 |
| 188 void Printer::Print(base::StringPiece str) { | 160 void Printer::Print(base::StringPiece str) { |
| 189 str.AppendToString(&output_); | 161 str.AppendToString(&output_); |
| 190 } | 162 } |
| 191 | 163 |
| 192 void Printer::PrintMargin() { | 164 void Printer::PrintMargin() { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 | 252 |
| 281 if (block->comments()) { | 253 if (block->comments()) { |
| 282 for (const auto& c : block->comments()->before()) { | 254 for (const auto& c : block->comments()->before()) { |
| 283 TrimAndPrintToken(c); | 255 TrimAndPrintToken(c); |
| 284 Newline(); | 256 Newline(); |
| 285 } | 257 } |
| 286 } | 258 } |
| 287 | 259 |
| 288 size_t i = 0; | 260 size_t i = 0; |
| 289 for (const auto& stmt : block->statements()) { | 261 for (const auto& stmt : block->statements()) { |
| 262 std::stringstream tmp; |
| 263 stmt->Print(tmp, 0); |
| 264 fprintf(stderr, "stmt: %s\n", tmp.str().c_str()); |
| 290 Expr(stmt, kPrecedenceLowest, false); | 265 Expr(stmt, kPrecedenceLowest, false); |
| 291 Newline(); | 266 Newline(); |
| 292 if (stmt->comments()) { | 267 if (stmt->comments()) { |
| 293 // Why are before() not printed here too? before() are handled inside | 268 // Why are before() not printed here too? before() are handled inside |
| 294 // Expr(), as are suffix() which are queued to the next Newline(). | 269 // Expr(), as are suffix() which are queued to the next Newline(). |
| 295 // However, because it's a general expression handler, it doesn't insert | 270 // However, because it's a general expression handler, it doesn't insert |
| 296 // the newline itself, which only happens between block statements. So, | 271 // the newline itself, which only happens between block statements. So, |
| 297 // the after are handled explicitly here. | 272 // the after are handled explicitly here. |
| 298 for (const auto& c : stmt->comments()->after()) { | 273 for (const auto& c : stmt->comments()->after()) { |
| 299 TrimAndPrintToken(c); | 274 TrimAndPrintToken(c); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 return result; | 308 return result; |
| 334 } | 309 } |
| 335 | 310 |
| 336 void Printer::AddParen(int prec, int outer_prec, bool* parenthesized) { | 311 void Printer::AddParen(int prec, int outer_prec, bool* parenthesized) { |
| 337 if (prec < outer_prec) { | 312 if (prec < outer_prec) { |
| 338 Print("("); | 313 Print("("); |
| 339 *parenthesized = true; | 314 *parenthesized = true; |
| 340 } | 315 } |
| 341 } | 316 } |
| 342 | 317 |
| 318 // This determines if the given node is something "statement-like". Generally |
| 319 // these are an assignment like 'sources = ["x"]' or a standalone function call |
| 320 // like 'import("xyz.gni")'. Some cases are slightly involved because the parse |
| 321 // tree is generic across binary operators which include both assignments that |
| 322 // are standalone statements, but also operators link &&, || which are not. |
| 323 // Additionally, function calls can mark statement boundaries when they're a |
| 324 // statement inside a block, but they may also be embedded for their return |
| 325 // value into the body of an expression (say, a rebase_path() in an expression). |
| 326 // |
| 327 // TODO: Maybe all the above is overly complicated, and it's just all the |
| 328 // direct children of BlockNodes + the false branch of ConditionNode. |
| 329 // |
| 330 // Breaking up into statements is used to segment into chunks. Line breaking and |
| 331 // indenting is done on a chunk basis, and one chunk does not affect another. |
| 332 bool Printer::IsStartOfStatement(const ParseNode* node) { |
| 333 // Is start of statement: |
| 334 // AccessorNode; // No |
| 335 // BinaryOpNode; // For =, +=, -=: Yes, else: No. |
| 336 // BlockCommentNode; // Yes |
| 337 // BlockNode; // No (?) just its statements. |
| 338 // ConditionNode; // Yes both arms. |
| 339 // EndNode; // No |
| 340 // FunctionCallNode; // Sometimes. This one is tricky. Maybe only when it's |
| 341 // // the immediate child of a BlockNode? |
| 342 // IdentifierNode; // No |
| 343 // ListNode; // No |
| 344 // LiteralNode; // No |
| 345 // UnaryOpNode; // No |
| 346 return false; |
| 347 } |
| 348 |
| 349 void DetermineLineBreaksForChunk() { |
| 350 } |
| 351 |
| 343 Printer::ExprStyle Printer::Expr(const ParseNode* root, | 352 Printer::ExprStyle Printer::Expr(const ParseNode* root, |
| 344 int outer_prec, | 353 int outer_prec, |
| 345 bool prefer_multiline) { | 354 bool prefer_multiline) { |
| 346 ExprStyle result = kExprStyleRegular; | 355 ExprStyle result = kExprStyleRegular; |
| 347 if (root->comments()) { | 356 if (root->comments()) { |
| 348 if (!root->comments()->before().empty()) { | 357 if (!root->comments()->before().empty()) { |
| 349 Trim(); | 358 Trim(); |
| 350 // If there's already other text on the line, start a new line. | 359 // If there's already other text on the line, start a new line. |
| 351 if (CurrentColumn() > 0) | 360 if (CurrentColumn() > 0) |
| 352 Print("\n"); | 361 Print("\n"); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 367 if (accessor->member()) { | 376 if (accessor->member()) { |
| 368 Print("."); | 377 Print("."); |
| 369 Expr(accessor->member(), kPrecedenceLowest, false); | 378 Expr(accessor->member(), kPrecedenceLowest, false); |
| 370 } else { | 379 } else { |
| 371 CHECK(accessor->index()); | 380 CHECK(accessor->index()); |
| 372 Print("["); | 381 Print("["); |
| 373 Expr(accessor->index(), kPrecedenceLowest, false); | 382 Expr(accessor->index(), kPrecedenceLowest, false); |
| 374 Print("]"); | 383 Print("]"); |
| 375 } | 384 } |
| 376 } else if (const BinaryOpNode* binop = root->AsBinaryOp()) { | 385 } else if (const BinaryOpNode* binop = root->AsBinaryOp()) { |
| 377 CHECK(precedence_.find(binop->op().value()) != precedence_.end()); | 386 Precedence prec = GetPrecedence(binop->op().value()); |
| 378 Precedence prec = precedence_[binop->op().value()]; | |
| 379 AddParen(prec, outer_prec, &parenthesized); | 387 AddParen(prec, outer_prec, &parenthesized); |
| 388 //FindLineBreakLocation(binop); |
| 380 Metrics right = GetLengthOfExpr( | 389 Metrics right = GetLengthOfExpr( |
| 381 binop->right(), prec + 1, IsAlwaysMultilineAssignment(binop)); | 390 binop->right(), prec + 1, IsAlwaysMultilineAssignment(binop)); |
| 382 int op_length = static_cast<int>(binop->op().value().size()) + 2; | 391 int op_length = static_cast<int>(binop->op().value().size()) + 2; |
| 383 Expr(binop->left(), prec, false); | 392 Expr(binop->left(), prec, false); |
| 384 if (CurrentColumn() + op_length + right.first_length <= kMaximumWidth) { | 393 if (CurrentColumn() + op_length + right.first_length <= kMaximumWidth) { |
| 385 // If it just fits normally, put it here. | 394 // If it just fits normally, put it here. |
| 386 Print(" "); | 395 Print(" "); |
| 387 Print(binop->op().value()); | 396 Print(binop->op().value()); |
| 388 Print(" "); | 397 Print(" "); |
| 389 Expr(binop->right(), prec + 1, IsAlwaysMultilineAssignment(binop)); | 398 Expr(binop->right(), prec + 1, IsAlwaysMultilineAssignment(binop)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 407 Sequence(kSequenceStyleBracedBlock, | 416 Sequence(kSequenceStyleBracedBlock, |
| 408 condition->if_true()->statements(), | 417 condition->if_true()->statements(), |
| 409 condition->if_true()->End(), | 418 condition->if_true()->End(), |
| 410 false); | 419 false); |
| 411 if (condition->if_false()) { | 420 if (condition->if_false()) { |
| 412 Print(" else "); | 421 Print(" else "); |
| 413 // If it's a block it's a bare 'else', otherwise it's an 'else if'. See | 422 // If it's a block it's a bare 'else', otherwise it's an 'else if'. See |
| 414 // ConditionNode::Execute. | 423 // ConditionNode::Execute. |
| 415 bool is_else_if = condition->if_false()->AsBlock() == NULL; | 424 bool is_else_if = condition->if_false()->AsBlock() == NULL; |
| 416 if (is_else_if) { | 425 if (is_else_if) { |
| 426 std::stringstream tmp; |
| 427 condition->if_false()->Print(tmp, 0); |
| 428 fprintf(stderr, "stmt4: %s\n", tmp.str().c_str()); |
| 417 Expr(condition->if_false(), kPrecedenceLowest, false); | 429 Expr(condition->if_false(), kPrecedenceLowest, false); |
| 418 } else { | 430 } else { |
| 419 Sequence(kSequenceStyleBracedBlock, | 431 Sequence(kSequenceStyleBracedBlock, |
| 420 condition->if_false()->AsBlock()->statements(), | 432 condition->if_false()->AsBlock()->statements(), |
| 421 condition->if_false()->AsBlock()->End(), | 433 condition->if_false()->AsBlock()->End(), |
| 422 false); | 434 false); |
| 423 } | 435 } |
| 424 } | 436 } |
| 425 } else if (const FunctionCallNode* func_call = root->AsFunctionCall()) { | 437 } else if (const FunctionCallNode* func_call = root->AsFunctionCall()) { |
| 426 FunctionCall(func_call); | 438 FunctionCall(func_call); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 // If there's before line comments, make sure we have a place to put them. | 489 // If there's before line comments, make sure we have a place to put them. |
| 478 for (const auto& i : list) { | 490 for (const auto& i : list) { |
| 479 if (i->comments() && !i->comments()->before().empty()) | 491 if (i->comments() && !i->comments()->before().empty()) |
| 480 force_multiline = true; | 492 force_multiline = true; |
| 481 } | 493 } |
| 482 | 494 |
| 483 if (list.size() == 0 && !force_multiline) { | 495 if (list.size() == 0 && !force_multiline) { |
| 484 // No elements, and not forcing newlines, print nothing. | 496 // No elements, and not forcing newlines, print nothing. |
| 485 } else if (list.size() == 1 && !force_multiline) { | 497 } else if (list.size() == 1 && !force_multiline) { |
| 486 Print(" "); | 498 Print(" "); |
| 499 if (style == kSequenceStyleBracedBlock) { |
| 500 std::stringstream tmp; |
| 501 list[0]->Print(tmp, 0); |
| 502 fprintf(stderr, "stmt2: %s\n", tmp.str().c_str()); |
| 503 } |
| 487 Expr(list[0], kPrecedenceLowest, false); | 504 Expr(list[0], kPrecedenceLowest, false); |
| 488 CHECK(!list[0]->comments() || list[0]->comments()->after().empty()); | 505 CHECK(!list[0]->comments() || list[0]->comments()->after().empty()); |
| 489 Print(" "); | 506 Print(" "); |
| 490 } else { | 507 } else { |
| 491 margin_ += kIndentSize; | 508 margin_ += kIndentSize; |
| 492 size_t i = 0; | 509 size_t i = 0; |
| 493 for (const auto& x : list) { | 510 for (const auto& x : list) { |
| 511 if (style == kSequenceStyleBracedBlock) { |
| 512 std::stringstream tmp; |
| 513 x->Print(tmp, 0); |
| 514 fprintf(stderr, "stmt3: %s\n", tmp.str().c_str()); |
| 515 } |
| 494 Newline(); | 516 Newline(); |
| 495 // If: | 517 // If: |
| 496 // - we're going to output some comments, and; | 518 // - we're going to output some comments, and; |
| 497 // - we haven't just started this multiline list, and; | 519 // - we haven't just started this multiline list, and; |
| 498 // - there isn't already a blank line here; | 520 // - there isn't already a blank line here; |
| 499 // Then: insert one. | 521 // Then: insert one. |
| 500 if (i != 0 && x->comments() && !x->comments()->before().empty() && | 522 if (i != 0 && x->comments() && !x->comments()->before().empty() && |
| 501 !HaveBlankLine()) { | 523 !HaveBlankLine()) { |
| 502 Newline(); | 524 Newline(); |
| 503 } | 525 } |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); | 815 printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); |
| 794 } else { | 816 } else { |
| 795 printf("%s", output_string.c_str()); | 817 printf("%s", output_string.c_str()); |
| 796 } | 818 } |
| 797 } | 819 } |
| 798 | 820 |
| 799 return 0; | 821 return 0; |
| 800 } | 822 } |
| 801 | 823 |
| 802 } // namespace commands | 824 } // namespace commands |
| OLD | NEW |