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 |