OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "tools/gn/line_breaker.h" |
| 6 |
| 7 #include "tools/gn/parse_tree.h" |
| 8 |
| 9 namespace commands { |
| 10 |
| 11 const int kExcessCharacterPenalty = 1000000; |
| 12 |
| 13 Precedence GetPrecedence(const base::StringPiece op) { |
| 14 if (op == "=" || op == "+=" || op == "-=") |
| 15 return kPrecedenceAssign; |
| 16 if (op == "||") |
| 17 return kPrecedenceOr; |
| 18 if (op == "&&") |
| 19 return kPrecedenceAnd; |
| 20 if (op == "<" || op == ">" || op == "==" || op == "!=" || op == "<=" || |
| 21 op == ">=") { |
| 22 return kPrecedenceCompare; |
| 23 } |
| 24 if (op == "+" || op == "-") |
| 25 return kPrecedenceAdd; |
| 26 if (op == "!") |
| 27 return kPrecedenceUnary; |
| 28 DCHECK(false); |
| 29 return kPrecedenceLowest; |
| 30 } |
| 31 |
| 32 AnnotatedToken::AnnotatedToken(const Token& token, Type type) |
| 33 : token_(token), type_(type) { |
| 34 } |
| 35 |
| 36 AnnotatedToken::~AnnotatedToken() { |
| 37 } |
| 38 |
| 39 void AddParen(int prec, |
| 40 int outer_prec, |
| 41 bool* parenthesized, |
| 42 std::vector<AnnotatedToken>* result) { |
| 43 if (prec < outer_prec) { |
| 44 result->push_back(AnnotatedToken(Token(Location(), Token::LEFT_PAREN, "("), |
| 45 AnnotatedToken::LEFT_PAREN_GROUPING)); |
| 46 *parenthesized = true; |
| 47 } |
| 48 } |
| 49 |
| 50 void FlattenUntilNextChunk(const ParseNode* root, |
| 51 int outer_prec, |
| 52 std::vector<AnnotatedToken>* result) { |
| 53 if (root) { |
| 54 bool parenthesized = false; |
| 55 if (const AccessorNode* accessor = root->AsAccessor()) { |
| 56 AddParen(kPrecedenceSuffix, outer_prec, &parenthesized, result); |
| 57 if (accessor->member()) { |
| 58 result->push_back(AnnotatedToken(Token(Location(), Token::DOT, "."), |
| 59 AnnotatedToken::UNDERLYING)); |
| 60 FlattenUntilNextChunk(accessor->member(), kPrecedenceLowest, result); |
| 61 } else { |
| 62 result->push_back( |
| 63 AnnotatedToken(Token(Location(), Token::LEFT_BRACKET, "["), |
| 64 AnnotatedToken::LEFT_BRACKET_ACCESSOR)); |
| 65 FlattenUntilNextChunk(accessor->index(), kPrecedenceLowest, result); |
| 66 result->push_back( |
| 67 AnnotatedToken(Token(Location(), Token::RIGHT_BRACKET, "]"), |
| 68 AnnotatedToken::UNDERLYING)); |
| 69 } |
| 70 } else if (const BinaryOpNode* binop = root->AsBinaryOp()) { |
| 71 Precedence prec = GetPrecedence(binop->op().value()); |
| 72 AddParen(prec, outer_prec, &parenthesized, result); |
| 73 FlattenUntilNextChunk(binop->left(), prec, result); |
| 74 result->push_back( |
| 75 AnnotatedToken(binop->op(), AnnotatedToken::UNDERLYING)); |
| 76 FlattenUntilNextChunk(binop->right(), prec + 1, result); |
| 77 } else if (const BlockNode* block = root->AsBlock()) { |
| 78 if (block->begin_token().type() != Token::INVALID) { |
| 79 result->push_back( |
| 80 AnnotatedToken(block->begin_token(), AnnotatedToken::UNDERLYING)); |
| 81 } |
| 82 // Don't walk rest after first. |
| 83 for (const auto& statement : block->statements()) { |
| 84 FlattenUntilNextChunk(statement, kPrecedenceLowest, result); |
| 85 break; |
| 86 } |
| 87 } else if (const ConditionNode* condition = root->AsConditionNode()) { |
| 88 FlattenUntilNextChunk(condition->condition(), kPrecedenceLowest, result); |
| 89 // Don't traverse into true/false as those count as breaks. |
| 90 } else if (const FunctionCallNode* func_call = root->AsFunctionCall()) { |
| 91 result->push_back( |
| 92 AnnotatedToken(func_call->function(), AnnotatedToken::UNDERLYING)); |
| 93 result->push_back( |
| 94 AnnotatedToken(func_call->args()->begin_token(), |
| 95 AnnotatedToken::LEFT_PAREN_FUNCTION_CALL)); |
| 96 size_t i = 0; |
| 97 for (const auto& node : func_call->args()->contents()) { |
| 98 FlattenUntilNextChunk(node, kPrecedenceLowest, result); |
| 99 if (i < func_call->args()->contents().size() - 1) { |
| 100 result->push_back(AnnotatedToken(Token(Location(), Token::COMMA, ","), |
| 101 AnnotatedToken::UNDERLYING)); |
| 102 } |
| 103 ++i; |
| 104 } |
| 105 FlattenUntilNextChunk(func_call->args()->End(), kPrecedenceLowest, |
| 106 result); |
| 107 } else if (const IdentifierNode* identifier = root->AsIdentifier()) { |
| 108 result->push_back( |
| 109 AnnotatedToken(identifier->value(), AnnotatedToken::UNDERLYING)); |
| 110 } else if (const ListNode* list = root->AsList()) { |
| 111 result->push_back(AnnotatedToken( |
| 112 list->begin_token(), AnnotatedToken::LEFT_BRACKET_LIST_LITERAL)); |
| 113 size_t i = 0; |
| 114 for (const auto& node : list->contents()) { |
| 115 FlattenUntilNextChunk(node, kPrecedenceLowest, result); |
| 116 if (i < list->contents().size() - 1) { |
| 117 result->push_back(AnnotatedToken(Token(Location(), Token::COMMA, ","), |
| 118 AnnotatedToken::UNDERLYING)); |
| 119 } |
| 120 ++i; |
| 121 } |
| 122 FlattenUntilNextChunk(list->End(), kPrecedenceLowest, result); |
| 123 } else if (const LiteralNode* literal = root->AsLiteral()) { |
| 124 result->push_back( |
| 125 AnnotatedToken(literal->value(), AnnotatedToken::UNDERLYING)); |
| 126 } else if (const UnaryOpNode* unaryop = root->AsUnaryOp()) { |
| 127 FlattenUntilNextChunk(unaryop->operand(), kPrecedenceUnary, result); |
| 128 } else if (const BlockCommentNode* comment = root->AsBlockComment()) { |
| 129 result->push_back( |
| 130 AnnotatedToken(comment->comment(), AnnotatedToken::UNDERLYING)); |
| 131 } else if (const EndNode* end = root->AsEnd()) { |
| 132 result->push_back( |
| 133 AnnotatedToken(end->value(), AnnotatedToken::UNDERLYING)); |
| 134 } else { |
| 135 CHECK(false) << "Unhandled case in FlattenUntilNextChunk."; |
| 136 } |
| 137 |
| 138 if (parenthesized) { |
| 139 result->push_back( |
| 140 AnnotatedToken(Token(Location(), Token::RIGHT_PAREN, ")"), |
| 141 AnnotatedToken::UNDERLYING)); |
| 142 } |
| 143 } |
| 144 } |
| 145 |
| 146 std::vector<AnnotatedToken> BuildAnnotatedTokenList( |
| 147 const ParseNode* statement) { |
| 148 std::vector<AnnotatedToken> result; |
| 149 FlattenUntilNextChunk(statement, kPrecedenceLowest, &result); |
| 150 return result; |
| 151 } |
| 152 |
| 153 LineBreaker::LineBreaker(const std::vector<AnnotatedToken>& annotated_tokens, |
| 154 int initial_column) |
| 155 : annotated_tokens_(annotated_tokens), |
| 156 initial_column_(initial_column), |
| 157 end_(static_cast<int>(annotated_tokens.size())) { |
| 158 } |
| 159 |
| 160 LineBreaker::~LineBreaker() { |
| 161 } |
| 162 |
| 163 std::string LineBreaker::GetBestLayout() { |
| 164 Format(0, initial_column_); |
| 165 return std::string(); |
| 166 } |
| 167 |
| 168 void LineBreaker::Format(int index, int start_column) { |
| 169 LineState state; |
| 170 state.column = start_column; |
| 171 state.next = index + 1; |
| 172 |
| 173 // todo move past first, it's already in place |
| 174 |
| 175 while (state.next < end_) { |
| 176 |
| 177 } |
| 178 } |
| 179 |
| 180 int LineBreaker::CalculatePenalty(LineState state, bool newline) { |
| 181 if (state.next == end_) |
| 182 return 0; |
| 183 |
| 184 int penalty = 0; |
| 185 |
| 186 AddTokenToState(newline, &state); |
| 187 |
| 188 // Assign penalty for being too long. |
| 189 if (state.column > kMaximumWidth) { |
| 190 int excess_characters = state.column - kMaximumWidth; |
| 191 penalty += excess_characters * kExcessCharacterPenalty; |
| 192 } |
| 193 |
| 194 int no_break = CalculatePenalty(state, false); |
| 195 int with_break = CalculatePenalty(state, true); |
| 196 int result = std::min(no_break, with_break); |
| 197 //penalty_cache_[state] = result; |
| 198 return result + penalty; |
| 199 } |
| 200 |
| 201 void LineBreaker::AddTokenToState(bool newline, LineState* state) { |
| 202 } |
| 203 |
| 204 } // namespace commands |
OLD | NEW |