Index: tools/gn/command_format.cc |
diff --git a/tools/gn/command_format.cc b/tools/gn/command_format.cc |
index f30984a14503cfef553c57623afa2f339d1879e2..c2870f1433a7cbec81d802bc8b557d378d0bbdf9 100644 |
--- a/tools/gn/command_format.cc |
+++ b/tools/gn/command_format.cc |
@@ -68,8 +68,8 @@ enum Precedence { |
kPrecedenceAnd, |
kPrecedenceCompare, |
kPrecedenceAdd, |
- kPrecedenceSuffix, |
kPrecedenceUnary, |
+ kPrecedenceSuffix, |
}; |
int CountLines(const std::string& str) { |
@@ -178,15 +178,23 @@ class Printer { |
} |
struct IndentState { |
- IndentState() : margin(0), continuation_requires_indent(false) {} |
- IndentState(int margin, bool continuation_requires_indent) |
+ IndentState() |
+ : margin(0), |
+ continuation_requires_indent(false), |
+ parent_is_boolean_or(false) {} |
+ IndentState(int margin, |
+ bool continuation_requires_indent, |
+ bool parent_is_boolean_or) |
: margin(margin), |
- continuation_requires_indent(continuation_requires_indent) {} |
+ continuation_requires_indent(continuation_requires_indent), |
+ parent_is_boolean_or(parent_is_boolean_or) {} |
// The left margin (number of spaces). |
int margin; |
bool continuation_requires_indent; |
+ |
+ bool parent_is_boolean_or; |
}; |
// Stack used to track |
std::vector<IndentState> stack_; |
@@ -239,7 +247,7 @@ void Printer::Newline() { |
// Save the margin, and temporarily set it to where the first comment |
// starts so that multiple suffix comments are vertically aligned. This |
// will need to be fancier once we enforce 80 col. |
- stack_.push_back(IndentState(CurrentColumn(), false)); |
+ stack_.push_back(IndentState(CurrentColumn(), false, false)); |
int i = 0; |
for (const auto& c : comments_) { |
if (i > 0) { |
@@ -413,8 +421,26 @@ int Printer::Expr(const ParseNode* root, |
} else if (const BinaryOpNode* binop = root->AsBinaryOp()) { |
CHECK(precedence_.find(binop->op().value()) != precedence_.end()); |
AnnotatePreferedMultilineAssignment(binop); |
+ |
Precedence prec = precedence_[binop->op().value()]; |
- AddParen(prec, outer_prec, &parenthesized); |
+ |
+ // Since binary operators format left-to-right, it is ok for the left side |
+ // use the same operator without parentheses, so the left uses prec. For the |
+ // same reason, the right side cannot reuse the same operator, or else "x + |
+ // (y + z)" would format as "x + y + z" which means "(x + y) + z". So, treat |
+ // the right expression as appearing one precedence level higher. |
+ // However, because the source parens are not in the parse tree, as a |
+ // special case for && and || we insert strictly-redundant-but-helpful-for- |
+ // human-readers parentheses. |
+ int prec_left = prec; |
+ int prec_right = prec + 1; |
+ if (binop->op().value() == "&&" && stack_.back().parent_is_boolean_or) { |
+ Print("("); |
+ parenthesized = true; |
+ } else { |
+ AddParen(prec_left, outer_prec, &parenthesized); |
+ } |
+ |
int start_line = CurrentLine(); |
int start_column = CurrentColumn(); |
bool is_assignment = binop->op().value() == "=" || |
@@ -434,11 +460,12 @@ int Printer::Expr(const ParseNode* root, |
if (stack_.back().continuation_requires_indent) |
indent_column += kIndentSize * 2; |
- stack_.push_back(IndentState(indent_column, false)); |
+ stack_.push_back( |
+ IndentState(indent_column, false, binop->op().value() == "||")); |
Printer sub_left; |
InitializeSub(&sub_left); |
sub_left.Expr(binop->left(), |
- prec, |
+ prec_left, |
std::string(" ") + binop->op().value().as_string()); |
bool left_is_multiline = CountLines(sub_left.String()) > 1; |
// Avoid walking the whole left redundantly times (see timing of Format.046) |
@@ -453,7 +480,7 @@ int Printer::Expr(const ParseNode* root, |
InitializeSub(&sub1); |
sub1.Print(" "); |
int penalty_current_line = |
- sub1.Expr(binop->right(), prec + 1, std::string()); |
+ sub1.Expr(binop->right(), prec_right, std::string()); |
sub1.Print(suffix); |
penalty_current_line += AssessPenalty(sub1.String()); |
if (!is_assignment && left_is_multiline) { |
@@ -467,19 +494,20 @@ int Printer::Expr(const ParseNode* root, |
Printer sub2; |
InitializeSub(&sub2); |
sub2.Newline(); |
- int penalty_next_line = sub2.Expr(binop->right(), prec + 1, std::string()); |
+ int penalty_next_line = |
+ sub2.Expr(binop->right(), prec_right, std::string()); |
sub2.Print(suffix); |
penalty_next_line += AssessPenalty(sub2.String()); |
if (penalty_current_line < penalty_next_line) { |
Print(" "); |
- Expr(binop->right(), prec + 1, std::string()); |
+ Expr(binop->right(), prec_right, std::string()); |
} else { |
// Otherwise, put first argument and op, and indent next. |
Newline(); |
penalty += std::abs(CurrentColumn() - start_column) * |
kPenaltyHorizontalSeparation; |
- Expr(binop->right(), prec + 1, std::string()); |
+ Expr(binop->right(), prec_right, std::string()); |
} |
stack_.pop_back(); |
penalty += (CurrentLine() - start_line) * GetPenaltyForLineBreak(); |
@@ -570,8 +598,9 @@ void Printer::Sequence(SequenceStyle style, |
CHECK(!list[0]->comments() || list[0]->comments()->after().empty()); |
Print(" "); |
} else { |
- stack_.push_back( |
- IndentState(margin() + kIndentSize, style == kSequenceStyleList)); |
+ stack_.push_back(IndentState(margin() + kIndentSize, |
+ style == kSequenceStyleList, |
+ false)); |
size_t i = 0; |
for (const auto& x : list) { |
Newline(); |
@@ -660,7 +689,7 @@ int Printer::FunctionCall(const FunctionCallNode* func_call, |
// 1: Same line. |
Printer sub1; |
InitializeSub(&sub1); |
- sub1.stack_.push_back(IndentState(CurrentColumn(), true)); |
+ sub1.stack_.push_back(IndentState(CurrentColumn(), true, false)); |
int penalty_one_line = 0; |
for (size_t i = 0; i < list.size(); ++i) { |
penalty_one_line += sub1.Expr(list[i], kPrecedenceLowest, |
@@ -677,7 +706,7 @@ int Printer::FunctionCall(const FunctionCallNode* func_call, |
// 2: Starting on same line, broken at commas. |
Printer sub2; |
InitializeSub(&sub2); |
- sub2.stack_.push_back(IndentState(CurrentColumn(), true)); |
+ sub2.stack_.push_back(IndentState(CurrentColumn(), true, false)); |
int penalty_multiline_start_same_line = 0; |
for (size_t i = 0; i < list.size(); ++i) { |
penalty_multiline_start_same_line += sub2.Expr( |
@@ -692,7 +721,7 @@ int Printer::FunctionCall(const FunctionCallNode* func_call, |
// 3: Starting on next line, broken at commas. |
Printer sub3; |
InitializeSub(&sub3); |
- sub3.stack_.push_back(IndentState(margin() + kIndentSize * 2, true)); |
+ sub3.stack_.push_back(IndentState(margin() + kIndentSize * 2, true, false)); |
sub3.Newline(); |
int penalty_multiline_start_next_line = 0; |
for (size_t i = 0; i < list.size(); ++i) { |
@@ -728,10 +757,10 @@ int Printer::FunctionCall(const FunctionCallNode* func_call, |
// No elements, and not forcing newlines, print nothing. |
} else { |
if (penalty_multiline_start_next_line < penalty_multiline_start_same_line) { |
- stack_.push_back(IndentState(margin() + kIndentSize * 2, true)); |
+ stack_.push_back(IndentState(margin() + kIndentSize * 2, true, false)); |
Newline(); |
} else { |
- stack_.push_back(IndentState(CurrentColumn(), true)); |
+ stack_.push_back(IndentState(CurrentColumn(), true, false)); |
} |
for (size_t i = 0; i < list.size(); ++i) { |