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 #ifndef TOOLS_GN_LINE_BREAKER_H_ |
| 6 #define TOOLS_GN_LINE_BREAKER_H_ |
| 7 |
| 8 #include <map> |
| 9 #include <string> |
| 10 #include <vector> |
| 11 |
| 12 #include "tools/gn/token.h" |
| 13 |
| 14 class ParseNode; |
| 15 |
| 16 namespace commands { |
| 17 |
| 18 enum { kIndentSize = 2 }; |
| 19 enum { kMaximumWidth = 2 }; |
| 20 |
| 21 enum Precedence { |
| 22 kPrecedenceLowest, |
| 23 kPrecedenceAssign, |
| 24 kPrecedenceOr, |
| 25 kPrecedenceAnd, |
| 26 kPrecedenceCompare, |
| 27 kPrecedenceAdd, |
| 28 kPrecedenceSuffix, |
| 29 kPrecedenceUnary, |
| 30 }; |
| 31 |
| 32 // Gives the precedence for operators in a BinaryOpNode. |
| 33 Precedence GetPrecedence(const base::StringPiece op); |
| 34 |
| 35 class AnnotatedToken { |
| 36 public: |
| 37 enum Type { |
| 38 UNDERLYING = Token::Type::NUM_TYPES, // Nothing additional on top of the |
| 39 // basic Token::Type; |
| 40 LEFT_PAREN_FUNCTION_CALL, |
| 41 LEFT_PAREN_GROUPING, |
| 42 LEFT_BRACKET_LIST_LITERAL, |
| 43 LEFT_BRACKET_ACCESSOR, |
| 44 }; |
| 45 |
| 46 AnnotatedToken(const Token& token, Type type); |
| 47 ~AnnotatedToken(); |
| 48 |
| 49 const base::StringPiece value() const { return token_.value(); } |
| 50 Type type() const { |
| 51 return type_ == UNDERLYING ? static_cast<Type>(token_.type()) : type_; |
| 52 } |
| 53 |
| 54 private: |
| 55 Token token_; |
| 56 Type type_; |
| 57 }; |
| 58 |
| 59 std::vector<AnnotatedToken> BuildAnnotatedTokenList(const ParseNode* statement); |
| 60 |
| 61 // This takes a subset of the parse tree that is considered to be one |
| 62 // "statement-like" thing, as well as the column offset at which it must start. |
| 63 // This might be something like an assignment 'sources = ["x"]' or the condition |
| 64 // in an 'if' statement. |
| 65 // |
| 66 // The chunk is a flat list of tokens with extra information about what kind |
| 67 // they are (for example, distinguishing between the '(' to start a function |
| 68 // call, vs. a '(' in a parenthesized expression). If any line break is |
| 69 // necessary to fit, try a line break between each item, summing up a penalty |
| 70 // value depending on where it's broken. The set of line breaks with the lowest |
| 71 // penalty score is chosen. |
| 72 // |
| 73 // One wrinkle is that we can't just do an exhaustive search because there are |
| 74 // commonly very long statements in .gn files. For 'sources = ["0", "1", "2", |
| 75 // ... "999"]' there's ~2000 possible line breaks inside the list. Checking all |
| 76 // possible line breaks would be 2^2000 permutations, and ain't nobody got time |
| 77 // for that. However, the penalty for ([tokenN..end] laid out at column M) is a |
| 78 // cacheable value, which makes the problem tractable. |
| 79 class LineBreaker { |
| 80 public: |
| 81 LineBreaker(const std::vector<AnnotatedToken>& annotated_tokens, |
| 82 int initial_column); |
| 83 ~LineBreaker(); |
| 84 |
| 85 std::string GetBestLayout(); |
| 86 |
| 87 private: |
| 88 struct LineState { |
| 89 int column; |
| 90 int next; |
| 91 }; |
| 92 void Format(int index, int start_column); |
| 93 |
| 94 int CalculatePenalty(LineState state, bool newline); |
| 95 void AddTokenToState(bool newline, LineState* state); |
| 96 |
| 97 struct CacheKey { |
| 98 int token_index; // The penalty is calculated from this token to the end of |
| 99 // the list. |
| 100 int column; |
| 101 }; |
| 102 typedef std::map<CacheKey, int> PenaltyCache; |
| 103 PenaltyCache penalty_cache_; |
| 104 |
| 105 const std::vector<AnnotatedToken>& annotated_tokens_; |
| 106 int initial_column_; |
| 107 int end_; |
| 108 |
| 109 DISALLOW_COPY_AND_ASSIGN(LineBreaker); |
| 110 }; |
| 111 |
| 112 } // namespace commands |
| 113 |
| 114 #endif // TOOLS_GN_LINE_BREAKER_H_ |
OLD | NEW |