Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: tools/gn/command_format.cc

Issue 742003002: gn format: penalty-based line breaking WIP XXX Base URL: https://chromium.googlesource.com/chromium/src.git@gn-more-disabled
Patch Set: futzing Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/BUILD.gn ('k') | tools/gn/format_test_data/032.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « tools/gn/BUILD.gn ('k') | tools/gn/format_test_data/032.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698