OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart_style.src.rule.rule; | 5 library dart_style.src.rule.rule; |
6 | 6 |
7 import '../chunk.dart'; | 7 import '../chunk.dart'; |
8 import '../fast_hash.dart'; | 8 import '../fast_hash.dart'; |
9 | 9 |
10 /// A constraint that determines the different ways a related set of chunks may | 10 /// A constraint that determines the different ways a related set of chunks may |
11 /// be split. | 11 /// be split. |
12 abstract class Rule extends FastHash { | 12 class Rule extends FastHash { |
13 /// Rule value that splits no chunks. | 13 /// Rule value that splits no chunks. |
14 /// | 14 /// |
15 /// Every rule is required to treat this value as fully unsplit. | 15 /// Every rule is required to treat this value as fully unsplit. |
16 static const unsplit = 0; | 16 static const unsplit = 0; |
17 | 17 |
18 /// Rule constraint value that means "any value as long as something splits". | 18 /// Rule constraint value that means "any value as long as something splits". |
19 /// | 19 /// |
20 /// It disallows [unsplit] but allows any other value. | 20 /// It disallows [unsplit] but allows any other value. |
21 static const mustSplit = -1; | 21 static const mustSplit = -1; |
22 | 22 |
23 /// The number of different states this rule can be in. | 23 /// The number of different states this rule can be in. |
24 /// | 24 /// |
25 /// Each state determines which set of chunks using this rule are split and | 25 /// Each state determines which set of chunks using this rule are split and |
26 /// which aren't. Values range from zero to one minus this. Value zero | 26 /// which aren't. Values range from zero to one minus this. Value zero |
27 /// always means "no chunks are split" and increasing values by convention | 27 /// always means "no chunks are split" and increasing values by convention |
28 /// mean increasingly undesirable splits. | 28 /// mean increasingly undesirable splits. |
29 int get numValues; | 29 /// |
| 30 /// By default, a rule has two values: fully unsplit and fully split. |
| 31 int get numValues => 2; |
30 | 32 |
31 /// The rule value that forces this rule into its maximally split state. | 33 /// The rule value that forces this rule into its maximally split state. |
32 /// | 34 /// |
33 /// By convention, this is the highest of the range of allowed values. | 35 /// By convention, this is the highest of the range of allowed values. |
34 int get fullySplitValue => numValues - 1; | 36 int get fullySplitValue => numValues - 1; |
35 | 37 |
36 int get cost => Cost.normal; | 38 final int cost; |
37 | 39 |
38 /// During line splitting [LineSplitter] sets this to the index of this | 40 /// During line splitting [LineSplitter] sets this to the index of this |
39 /// rule in its list of rules. | 41 /// rule in its list of rules. |
40 int index; | 42 int index; |
41 | 43 |
| 44 /// If `true`, the rule has been "hardened" meaning it's been placed into a |
| 45 /// permanent "must fully split" state. |
| 46 bool get isHardened => _isHardened; |
| 47 bool _isHardened = false; |
| 48 |
42 /// The other [Rule]s that "surround" this one (and care about that fact). | 49 /// The other [Rule]s that "surround" this one (and care about that fact). |
43 /// | 50 /// |
44 /// In many cases, if a split occurs inside an expression, surrounding rules | 51 /// In many cases, if a split occurs inside an expression, surrounding rules |
45 /// also want to split too. For example, a split in the middle of an argument | 52 /// also want to split too. For example, a split in the middle of an argument |
46 /// forces the entire argument list to also split. | 53 /// forces the entire argument list to also split. |
47 /// | 54 /// |
48 /// This tracks those relationships. If this rule splits, (sets its value to | 55 /// This tracks those relationships. If this rule splits, (sets its value to |
49 /// [fullySplitValue]) then all of the outer rules will also be set to their | 56 /// [fullySplitValue]) then all of the outer rules will also be set to their |
50 /// fully split value. | 57 /// fully split value. |
51 /// | 58 /// |
(...skipping 10 matching lines...) Expand all Loading... |
62 inner._outerRules.add(this); | 69 inner._outerRules.add(this); |
63 } | 70 } |
64 | 71 |
65 /// Whether this rule cares about rules that it contains. | 72 /// Whether this rule cares about rules that it contains. |
66 /// | 73 /// |
67 /// If `true` then inner rules will constrain this one and force it to split | 74 /// If `true` then inner rules will constrain this one and force it to split |
68 /// when they split. Otherwise, it can split independently of any contained | 75 /// when they split. Otherwise, it can split independently of any contained |
69 /// rules. | 76 /// rules. |
70 bool get splitsOnInnerRules => true; | 77 bool get splitsOnInnerRules => true; |
71 | 78 |
72 bool isSplit(int value, Chunk chunk); | 79 Rule([int cost]) : cost = cost ?? Cost.normal; |
| 80 |
| 81 /// Creates a new rule that is already fully split. |
| 82 Rule.hard() : cost = 0 { |
| 83 // Set the cost to zero since it will always be applied, so there's no |
| 84 // point in penalizing it. |
| 85 // |
| 86 // Also, this avoids doubled counting in literal blocks where there is both |
| 87 // a split in the outer chunk containing the block and the inner hard split |
| 88 // between the elements or statements. |
| 89 harden(); |
| 90 } |
| 91 |
| 92 /// Fixes this rule into a "fully split" state. |
| 93 void harden() { |
| 94 _isHardened = true; |
| 95 } |
| 96 |
| 97 /// Returns `true` if [chunk] should split when this rule has [value]. |
| 98 bool isSplit(int value, Chunk chunk) { |
| 99 if (_isHardened) return true; |
| 100 |
| 101 if (value == Rule.unsplit) return false; |
| 102 |
| 103 // Let the subclass decide. |
| 104 return isSplitAtValue(value, chunk); |
| 105 } |
| 106 |
| 107 /// Subclasses can override this to determine which values split which chunks. |
| 108 /// |
| 109 /// By default, this assumes every chunk splits. |
| 110 bool isSplitAtValue(value, chunk) => true; |
73 | 111 |
74 /// Given that this rule has [value], determine if [other]'s value should be | 112 /// Given that this rule has [value], determine if [other]'s value should be |
75 /// constrained. | 113 /// constrained. |
76 /// | 114 /// |
77 /// Allows relationships between rules like "if I split, then this should | 115 /// Allows relationships between rules like "if I split, then this should |
78 /// split too". Returns a non-negative value to force [other] to take that | 116 /// split too". Returns a non-negative value to force [other] to take that |
79 /// value. Returns -1 to allow [other] to take any non-zero value. Returns | 117 /// value. Returns -1 to allow [other] to take any non-zero value. Returns |
80 /// null to not constrain other. | 118 /// null to not constrain other. |
81 int constrain(int value, Rule other) { | 119 int constrain(int value, Rule other) { |
82 // By default, any containing rule will be fully split if this one is split. | 120 // By default, any containing rule will be fully split if this one is split. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 visit(this); | 177 visit(this); |
140 } | 178 } |
141 | 179 |
142 return _allConstrainedRules; | 180 return _allConstrainedRules; |
143 } | 181 } |
144 | 182 |
145 Set<Rule> _allConstrainedRules; | 183 Set<Rule> _allConstrainedRules; |
146 | 184 |
147 String toString() => "$id"; | 185 String toString() => "$id"; |
148 } | 186 } |
149 | |
150 /// A rule that always splits a chunk. | |
151 class HardSplitRule extends Rule { | |
152 int get numValues => 1; | |
153 | |
154 /// It's always going to be applied, so there's no point in penalizing it. | |
155 /// | |
156 /// Also, this avoids doubled counting in literal blocks where there is both | |
157 /// a split in the outer chunk containing the block and the inner hard split | |
158 /// between the elements or statements. | |
159 int get cost => 0; | |
160 | |
161 /// It's always split anyway. | |
162 bool get splitsOnInnerRules => false; | |
163 | |
164 bool isSplit(int value, Chunk chunk) => true; | |
165 | |
166 String toString() => "Hard"; | |
167 } | |
168 | |
169 /// A basic rule that has two states: unsplit or split. | |
170 class SimpleRule extends Rule { | |
171 /// Two values: 0 is unsplit, 1 is split. | |
172 int get numValues => 2; | |
173 | |
174 final int cost; | |
175 | |
176 SimpleRule([int cost]) : cost = cost != null ? cost : Cost.normal; | |
177 | |
178 bool isSplit(int value, Chunk chunk) => value != Rule.unsplit; | |
179 | |
180 String toString() => "Simple${super.toString()}"; | |
181 } | |
OLD | NEW |