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.argument; | 5 library dart_style.src.rule.argument; |
6 | 6 |
7 import '../chunk.dart'; | 7 import '../chunk.dart'; |
8 import 'rule.dart'; | 8 import 'rule.dart'; |
9 | 9 |
10 /// Base class for a rule that handles argument or parameter lists. | 10 /// Base class for a rule that handles argument or parameter lists. |
11 abstract class ArgumentRule extends Rule { | 11 abstract class ArgumentRule extends Rule { |
| 12 /// The chunks prior to each positional argument. |
| 13 final List<Chunk> _arguments = []; |
| 14 |
12 /// The rule used to split collections in the argument list, if any. | 15 /// The rule used to split collections in the argument list, if any. |
13 final Rule _collectionRule; | 16 Rule _collectionRule; |
| 17 |
| 18 /// The number of leading collection arguments. |
| 19 /// |
| 20 /// This and [_trailingCollections] cannot both be positive. If every |
| 21 /// argument is a collection, this will be [_arguments.length] and |
| 22 /// [_trailingCollections] will be 0. |
| 23 final int _leadingCollections; |
| 24 |
| 25 /// The number of trailing collections. |
| 26 /// |
| 27 /// This and [_leadingCollections] cannot both be positive. |
| 28 final int _trailingCollections; |
14 | 29 |
15 /// If true, then inner rules that are written will force this rule to split. | 30 /// If true, then inner rules that are written will force this rule to split. |
16 /// | 31 /// |
17 /// Temporarily disabled while writing collectio arguments so that they can be | 32 /// Temporarily disabled while writing collectio arguments so that they can be |
18 /// multi-line without forcing the whole argument list to split. | 33 /// multi-line without forcing the whole argument list to split. |
19 bool _trackInnerRules = true; | 34 bool _trackInnerRules = true; |
20 | 35 |
21 /// Don't split when an inner collection rule splits. | 36 /// Don't split when an inner collection rule splits. |
22 bool get splitsOnInnerRules => _trackInnerRules; | 37 bool get splitsOnInnerRules => _trackInnerRules; |
23 | 38 |
24 /// Creates a new rule for a positional argument list. | 39 ArgumentRule(this._collectionRule, this._leadingCollections, |
25 /// | 40 this._trailingCollections); |
26 /// If [_collectionRule] is given, it is the rule used to split the | 41 |
27 /// collections in the list. | 42 void addConstrainedRules(Set<Rule> rules) { |
28 ArgumentRule(this._collectionRule); | 43 super.addConstrainedRules(rules); |
| 44 if (_collectionRule != null) rules.add(_collectionRule); |
| 45 } |
| 46 |
| 47 void forgetUnusedRules() { |
| 48 super.forgetUnusedRules(); |
| 49 if (_collectionRule != null && _collectionRule.index == null) { |
| 50 _collectionRule = null; |
| 51 } |
| 52 } |
| 53 |
| 54 /// Remembers [chunk] as containing the split that occurs right before an |
| 55 /// argument in the list. |
| 56 void beforeArgument(Chunk chunk) { |
| 57 _arguments.add(chunk); |
| 58 } |
29 | 59 |
30 /// Called before a collection argument is written. | 60 /// Called before a collection argument is written. |
31 /// | 61 /// |
32 /// Disables tracking inner rules while a collection argument is written. | 62 /// Disables tracking inner rules while a collection argument is written. |
33 void beforeCollection() { | 63 void beforeCollection() { |
34 assert(_trackInnerRules == true); | 64 assert(_trackInnerRules == true); |
35 _trackInnerRules = false; | 65 _trackInnerRules = false; |
36 } | 66 } |
37 | 67 |
38 /// Called after a collection argument is complete. | 68 /// Called after a collection argument is complete. |
39 /// | 69 /// |
40 /// Re-enables tracking inner rules. | 70 /// Re-enables tracking inner rules. |
41 void afterCollection() { | 71 void afterCollection() { |
42 assert(_trackInnerRules == false); | 72 assert(_trackInnerRules == false); |
43 _trackInnerRules = true; | 73 _trackInnerRules = true; |
44 } | 74 } |
45 } | 75 } |
46 | 76 |
47 /// Base class for a rule for handling positional argument lists. | 77 /// Base class for a rule for handling positional argument lists. |
48 abstract class PositionalRule extends ArgumentRule { | 78 abstract class PositionalRule extends ArgumentRule { |
49 /// The chunks prior to each positional argument. | |
50 final List<Chunk> _arguments = []; | |
51 | |
52 /// If there are named arguments following these positional ones, this will | 79 /// If there are named arguments following these positional ones, this will |
53 /// be their rule. | 80 /// be their rule. |
54 Rule _namedArgsRule; | 81 Rule _namedArgsRule; |
55 | 82 |
56 /// Creates a new rule for a positional argument list. | 83 /// Creates a new rule for a positional argument list. |
57 /// | 84 /// |
58 /// If [collectionRule] is given, it is the rule used to split the collection | 85 /// If [_collectionRule] is given, it is the rule used to split the collection |
59 /// arguments in the list. | 86 /// arguments in the list. |
60 PositionalRule(Rule collectionRule) : super(collectionRule); | 87 PositionalRule( |
| 88 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 89 : super(collectionRule, leadingCollections, trailingCollections); |
61 | 90 |
62 /// Remembers [chunk] as containing the split that occurs right before an | 91 void addConstrainedRules(Set<Rule> rules) { |
63 /// argument in the list. | 92 super.addConstrainedRules(rules); |
64 void beforeArgument(Chunk chunk) { | 93 if (_namedArgsRule != null) rules.add(_namedArgsRule); |
65 _arguments.add(chunk); | |
66 } | 94 } |
67 | 95 |
68 /// Remembers that [rule] is the [NamedArgsRule] immediately following this | 96 void forgetUnusedRules() { |
| 97 super.forgetUnusedRules(); |
| 98 if (_namedArgsRule != null && _namedArgsRule.index == null) { |
| 99 _namedArgsRule = null; |
| 100 } |
| 101 } |
| 102 |
| 103 /// Remembers that [rule] is the [Rule] immediately following this positional |
69 /// positional argument list. | 104 /// positional argument list. |
70 void setNamedArgsRule(NamedRule rule) { | 105 /// |
| 106 /// This is normally a [NamedRule] but [PositionalRule] is also used for the |
| 107 /// property accesses at the beginning of a call chain, in which case this |
| 108 /// is just a [SimpleRule]. |
| 109 void setNamedArgsRule(Rule rule) { |
71 _namedArgsRule = rule; | 110 _namedArgsRule = rule; |
72 } | 111 } |
73 | 112 |
74 /// Constrains the named argument list to at least move to the next line if | 113 /// Constrains the named argument list to at least move to the next line if |
75 /// there are any splits in the positional arguments. Prevents things like: | 114 /// there are any splits in the positional arguments. Prevents things like: |
76 /// | 115 /// |
77 /// function( | 116 /// function( |
78 /// argument, | 117 /// argument, |
79 /// argument, named: argument); | 118 /// argument, named: argument); |
80 int constrain(int value, Rule other) { | 119 int constrain(int value, Rule other) { |
(...skipping 16 matching lines...) Expand all Loading... |
97 | 136 |
98 /// Split rule for a call with a single positional argument (which may or may | 137 /// Split rule for a call with a single positional argument (which may or may |
99 /// not be a collection argument.) | 138 /// not be a collection argument.) |
100 class SinglePositionalRule extends PositionalRule { | 139 class SinglePositionalRule extends PositionalRule { |
101 int get numValues => 2; | 140 int get numValues => 2; |
102 | 141 |
103 /// If there is only a single non-collection argument, allow it to split | 142 /// If there is only a single non-collection argument, allow it to split |
104 /// internally without forcing a split before the argument. | 143 /// internally without forcing a split before the argument. |
105 final bool splitsOnInnerRules; | 144 final bool splitsOnInnerRules; |
106 | 145 |
107 bool hack = false; | |
108 | |
109 /// Creates a new rule for a positional argument list. | 146 /// Creates a new rule for a positional argument list. |
110 /// | 147 /// |
111 /// If [collectionRule] is given, it is the rule used to split the | 148 /// If [collectionRule] is given, it is the rule used to split the |
112 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will | 149 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will |
113 /// split before the argument if the argument itself contains a split. | 150 /// split before the argument if the argument itself contains a split. |
114 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) | 151 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) |
115 : super(collectionRule), | 152 : super(collectionRule, 0, 0), |
116 splitsOnInnerRules = | 153 splitsOnInnerRules = |
117 splitsOnInnerRules != null ? splitsOnInnerRules : false; | 154 splitsOnInnerRules != null ? splitsOnInnerRules : false; |
118 | 155 |
119 bool isSplit(int value, Chunk chunk) => value == 1; | |
120 | |
121 int constrain(int value, Rule other) { | 156 int constrain(int value, Rule other) { |
122 var constrained = super.constrain(value, other); | 157 var constrained = super.constrain(value, other); |
123 if (constrained != null) return constrained; | 158 if (constrained != null) return constrained; |
124 | 159 |
125 if (other != _collectionRule) return null; | 160 if (other != _collectionRule) return null; |
126 | 161 |
127 // If we aren't splitting any args, we can split the collection. | 162 // If we aren't splitting any args, we can split the collection. |
128 if (value == 0) return null; | 163 if (value == Rule.unsplit) return null; |
129 | 164 |
130 // We are splitting before a collection, so don't let it split internally. | 165 // We are splitting before a collection, so don't let it split internally. |
131 return 0; | 166 return Rule.unsplit; |
132 } | 167 } |
133 | 168 |
134 String toString() => "1Pos${super.toString()}"; | 169 String toString() => "1Pos${super.toString()}"; |
135 } | 170 } |
136 | 171 |
137 /// Split rule for a call with more than one positional argument. | 172 /// Split rule for a call with more than one positional argument. |
138 /// | 173 /// |
139 /// The number of values is based on the number of arguments and whether or not | 174 /// The number of values is based on the number of arguments and whether or not |
140 /// there are bodies. The first two values are always: | 175 /// there are bodies. The first two values are always: |
141 /// | 176 /// |
142 /// * 0: Do not split at all. | 177 /// * 0: Do not split at all. |
143 /// * 1: Split only before the first argument. | 178 /// * 1: Split only before the first argument. |
144 /// | 179 /// |
145 /// Then there is a value for each argument, to split before that argument. | 180 /// Then there is a value for each argument, to split before that argument. |
146 /// These values work back to front. So, for a two-argument list, value 2 splits | 181 /// These values work back to front. So, for a two-argument list, value 2 splits |
147 /// after the second argument and value 3 splits after the first. | 182 /// after the second argument and value 3 splits after the first. |
148 /// | 183 /// |
149 /// Then there is a value that splits before every argument. | 184 /// Then there is a value that splits before every argument. |
150 /// | 185 /// |
151 /// Finally, if there are collection arguments, there is another value that | 186 /// Finally, if there are collection arguments, there is another value that |
152 /// splits before all of the non-collection arguments, but does not split | 187 /// splits before all of the non-collection arguments, but does not split |
153 /// before the collections, so that they can split internally. | 188 /// before the collections, so that they can split internally. |
154 class MultiplePositionalRule extends PositionalRule { | 189 class MultiplePositionalRule extends PositionalRule { |
155 /// The number of leading collection arguments. | |
156 /// | |
157 /// This and [_trailingCollections] cannot both be positive. If every | |
158 /// argument is a collection, this will be [_arguments.length] and | |
159 /// [_trailingCollections] will be 0. | |
160 final int _leadingCollections; | |
161 | |
162 /// The number of trailing collections. | |
163 /// | |
164 /// This and [_leadingCollections] cannot both be positive. | |
165 final int _trailingCollections; | |
166 | |
167 int get numValues { | 190 int get numValues { |
168 // Can split before any one argument, none, or all. | 191 // Can split before any one argument, none, or all. |
169 var result = 2 + _arguments.length; | 192 var result = 2 + _arguments.length; |
170 | 193 |
171 // When there are collection arguments, there are two ways we can split on | 194 // When there are collection arguments, there are two ways we can split on |
172 // "all" arguments: | 195 // "all" arguments: |
173 // | 196 // |
174 // - Split on just the non-collection arguments, and force the collection | 197 // - Split on just the non-collection arguments, and force the collection |
175 // arguments to split internally. | 198 // arguments to split internally. |
176 // - Split on all of them including the collection arguments, and do not | 199 // - Split on all of them including the collection arguments, and do not |
177 // allow the collection arguments to split internally. | 200 // allow the collection arguments to split internally. |
178 if (_leadingCollections > 0 || _trailingCollections > 0) result++; | 201 if (_leadingCollections > 0 || _trailingCollections > 0) result++; |
179 | 202 |
180 return result; | 203 return result; |
181 } | 204 } |
182 | 205 |
183 MultiplePositionalRule( | 206 MultiplePositionalRule( |
184 Rule collectionRule, this._leadingCollections, this._trailingCollections) | 207 Rule collectionRule, int leadingCollections, int trailingCollections) |
185 : super(collectionRule); | 208 : super(collectionRule, leadingCollections, trailingCollections); |
186 | 209 |
187 String toString() => "*Pos${super.toString()}"; | 210 String toString() => "*Pos${super.toString()}"; |
188 | 211 |
189 bool isSplit(int value, Chunk chunk) { | 212 bool isSplitAtValue(int value, Chunk chunk) { |
190 // Don't split at all. | |
191 if (value == 0) return false; | |
192 | |
193 // Split only before the first argument. Keep the entire argument list | 213 // Split only before the first argument. Keep the entire argument list |
194 // together on the next line. | 214 // together on the next line. |
195 if (value == 1) return chunk == _arguments.first; | 215 if (value == 1) return chunk == _arguments.first; |
196 | 216 |
197 // Split before a single argument. Try later arguments before earlier ones | 217 // Split before a single argument. Try later arguments before earlier ones |
198 // to try to keep as much on the first line as possible. | 218 // to try to keep as much on the first line as possible. |
199 if (value <= _arguments.length) { | 219 if (value <= _arguments.length) { |
200 var argument = _arguments.length - value + 1; | 220 var argument = _arguments.length - value + 1; |
201 return chunk == _arguments[argument]; | 221 return chunk == _arguments[argument]; |
202 } | 222 } |
(...skipping 14 matching lines...) Expand all Loading... |
217 } | 237 } |
218 | 238 |
219 // Split before all of the arguments, even the collections. | 239 // Split before all of the arguments, even the collections. |
220 return true; | 240 return true; |
221 } | 241 } |
222 | 242 |
223 int constrain(int value, Rule other) { | 243 int constrain(int value, Rule other) { |
224 var constrained = super.constrain(value, other); | 244 var constrained = super.constrain(value, other); |
225 if (constrained != null) return constrained; | 245 if (constrained != null) return constrained; |
226 | 246 |
| 247 // Decide how to constrain the collection rule. |
227 if (other != _collectionRule) return null; | 248 if (other != _collectionRule) return null; |
228 | 249 |
| 250 // If all of the collections are in the named arguments, [_collectionRule] |
| 251 // will not be null, but we don't have to handle it. |
| 252 if (_leadingCollections == 0 && _trailingCollections == 0) return null; |
| 253 |
229 // If we aren't splitting any args, we can split the collection. | 254 // If we aren't splitting any args, we can split the collection. |
230 if (value == 0) return null; | 255 if (value == Rule.unsplit) return null; |
231 | 256 |
232 // Split only before the first argument. | 257 // Split only before the first argument. |
233 if (value == 1) { | 258 if (value == 1) { |
234 if (_leadingCollections > 0) { | 259 if (_leadingCollections > 0) { |
235 // We are splitting before a collection, so don't let it split | 260 // We are splitting before a collection, so don't let it split |
236 // internally. | 261 // internally. |
237 return 0; | 262 return Rule.unsplit; |
238 } else { | 263 } else { |
239 // The split is outside of the collections so they can split or not. | 264 // The split is outside of the collections so they can split or not. |
240 return null; | 265 return null; |
241 } | 266 } |
242 } | 267 } |
243 | 268 |
244 // Split before a single argument. If it's in the middle of the collection | 269 // Split before a single argument. If it's in the middle of the collection |
245 // arguments, don't allow them to split. | 270 // arguments, don't allow them to split. |
246 if (value <= _arguments.length) { | 271 if (value <= _arguments.length) { |
247 var argument = _arguments.length - value + 1; | 272 var argument = _arguments.length - value + 1; |
248 if (argument < _leadingCollections) return 0; | 273 if (argument < _leadingCollections || |
249 if (argument >= _arguments.length - _trailingCollections) return 0; | 274 argument >= _arguments.length - _trailingCollections) { |
| 275 return Rule.unsplit; |
| 276 } |
250 | 277 |
251 return null; | 278 return null; |
252 } | 279 } |
253 | 280 |
254 // Only split before the non-collection arguments. This case only comes into | 281 // Only split before the non-collection arguments. This case only comes into |
255 // play when we do want to split the collection, so force that here. | 282 // play when we do want to split the collection, so force that here. |
256 if (value == _arguments.length + 1) return 1; | 283 if (value == _arguments.length + 1) return 1; |
257 | 284 |
258 // Split before all of the arguments, even the collection, so don't let | 285 // Split before all of the arguments, even the collections. We'll allow |
259 // them split. | 286 // them to split but indent their bodies if they do. |
260 return 0; | 287 return null; |
261 } | 288 } |
262 } | 289 } |
263 | 290 |
264 /// Splitting rule for a list of named arguments or parameters. Its values mean: | 291 /// Splitting rule for a list of named arguments or parameters. Its values mean: |
265 /// | 292 /// |
266 /// * 0: Do not split at all. | 293 /// * Do not split at all. |
267 /// * 1: Split only before first argument. | 294 /// * Split only before first argument. |
268 /// * 2: Split before all arguments, including the first. | 295 /// * Split before all arguments. |
269 class NamedRule extends ArgumentRule { | 296 class NamedRule extends ArgumentRule { |
270 /// The chunk prior to the first named argument. | |
271 Chunk _first; | |
272 | |
273 int get numValues => 3; | 297 int get numValues => 3; |
274 | 298 |
275 NamedRule(Rule collectionRule) : super(collectionRule); | 299 NamedRule( |
| 300 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 301 : super(collectionRule, leadingCollections, trailingCollections); |
276 | 302 |
277 void beforeArguments(Chunk chunk) { | 303 bool isSplitAtValue(int value, Chunk chunk) { |
278 assert(_first == null); | 304 // Move all arguments to the second line as a unit. |
279 _first = chunk; | 305 if (value == 1) return chunk == _arguments.first; |
280 } | |
281 | 306 |
282 bool isSplit(int value, Chunk chunk) { | 307 // Otherwise, split before all arguments. |
283 switch (value) { | 308 return true; |
284 case 0: | |
285 return false; | |
286 case 1: | |
287 return chunk == _first; | |
288 case 2: | |
289 return true; | |
290 } | |
291 | |
292 throw "unreachable"; | |
293 } | 309 } |
294 | 310 |
295 int constrain(int value, Rule other) { | 311 int constrain(int value, Rule other) { |
296 var constrained = super.constrain(value, other); | 312 var constrained = super.constrain(value, other); |
297 if (constrained != null) return constrained; | 313 if (constrained != null) return constrained; |
298 | 314 |
| 315 // Decide how to constrain the collection rule. |
299 if (other != _collectionRule) return null; | 316 if (other != _collectionRule) return null; |
300 | 317 |
| 318 // If all of the collections are in the named arguments, [_collectionRule] |
| 319 // will not be null, but we don't have to handle it. |
| 320 if (_leadingCollections == 0 && _trailingCollections == 0) return null; |
| 321 |
301 // If we aren't splitting any args, we can split the collection. | 322 // If we aren't splitting any args, we can split the collection. |
302 if (value == 0) return null; | 323 if (value == Rule.unsplit) return null; |
303 | 324 |
304 // Split before all of the arguments, even the collections, so don't let | 325 // Split only before the first argument. Don't allow the collections to |
305 // them split. | 326 // split. |
306 return 0; | 327 if (value == 1) return Rule.unsplit; |
| 328 |
| 329 // Split before all of the arguments, even the collections. We'll allow |
| 330 // them to split but indent their bodies if they do. |
| 331 return null; |
307 } | 332 } |
308 | 333 |
309 String toString() => "Named${super.toString()}"; | 334 String toString() => "Named${super.toString()}"; |
310 } | 335 } |
OLD | NEW |