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 |
| 15 /// The rule used to split collections in the argument list, if any. |
| 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; |
| 29 |
12 /// 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. |
13 /// | 31 /// |
14 /// Temporarily disabled while writing collectio arguments so that they can be | 32 /// Temporarily disabled while writing collectio arguments so that they can be |
15 /// multi-line without forcing the whole argument list to split. | 33 /// multi-line without forcing the whole argument list to split. |
16 bool _trackInnerRules = true; | 34 bool _trackInnerRules = true; |
17 | 35 |
18 /// Don't split when an inner collection rule splits. | 36 /// Don't split when an inner collection rule splits. |
19 bool get splitsOnInnerRules => _trackInnerRules; | 37 bool get splitsOnInnerRules => _trackInnerRules; |
20 | 38 |
| 39 ArgumentRule(this._collectionRule, this._leadingCollections, |
| 40 this._trailingCollections); |
| 41 |
| 42 void addConstrainedRules(Set<Rule> rules) { |
| 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 } |
| 59 |
21 /// Called before a collection argument is written. | 60 /// Called before a collection argument is written. |
22 /// | 61 /// |
23 /// Disables tracking inner rules while a collection argument is written. | 62 /// Disables tracking inner rules while a collection argument is written. |
24 void beforeCollection() { | 63 void beforeCollection() { |
25 assert(_trackInnerRules == true); | 64 assert(_trackInnerRules == true); |
26 _trackInnerRules = false; | 65 _trackInnerRules = false; |
27 } | 66 } |
28 | 67 |
29 /// Called after a collection argument is complete. | 68 /// Called after a collection argument is complete. |
30 /// | 69 /// |
31 /// Re-enables tracking inner rules. | 70 /// Re-enables tracking inner rules. |
32 void afterCollection() { | 71 void afterCollection() { |
33 assert(_trackInnerRules == false); | 72 assert(_trackInnerRules == false); |
34 _trackInnerRules = true; | 73 _trackInnerRules = true; |
35 } | 74 } |
36 } | 75 } |
37 | 76 |
38 /// Base class for a rule for handling positional argument lists. | 77 /// Base class for a rule for handling positional argument lists. |
39 abstract class PositionalRule extends ArgumentRule { | 78 abstract class PositionalRule extends ArgumentRule { |
40 /// The chunks prior to each positional argument. | |
41 final List<Chunk> _arguments = []; | |
42 | |
43 /// The rule used to split collections in the argument list, if any. | |
44 Rule _collectionRule; | |
45 | |
46 /// If there are named arguments following these positional ones, this will | 79 /// If there are named arguments following these positional ones, this will |
47 /// be their rule. | 80 /// be their rule. |
48 Rule _namedArgsRule; | 81 Rule _namedArgsRule; |
49 | 82 |
50 /// Creates a new rule for a positional argument list. | 83 /// Creates a new rule for a positional argument list. |
51 /// | 84 /// |
52 /// 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 |
53 /// arguments in the list. | 86 /// arguments in the list. |
54 PositionalRule(this._collectionRule); | 87 PositionalRule( |
| 88 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 89 : super(collectionRule, leadingCollections, trailingCollections); |
55 | 90 |
56 void addConstrainedRules(Set<Rule> rules) { | 91 void addConstrainedRules(Set<Rule> rules) { |
57 if (_collectionRule != null) rules.add(_collectionRule); | 92 super.addConstrainedRules(rules); |
58 if (_namedArgsRule != null) rules.add(_namedArgsRule); | 93 if (_namedArgsRule != null) rules.add(_namedArgsRule); |
59 } | 94 } |
60 | 95 |
61 void forgetUnusedRules() { | 96 void forgetUnusedRules() { |
62 super.forgetUnusedRules(); | 97 super.forgetUnusedRules(); |
63 if (_namedArgsRule != null && _namedArgsRule.index == null) { | 98 if (_namedArgsRule != null && _namedArgsRule.index == null) { |
64 _namedArgsRule = null; | 99 _namedArgsRule = null; |
65 } | 100 } |
66 | |
67 if (_collectionRule != null && _collectionRule.index == null) { | |
68 _collectionRule = null; | |
69 } | |
70 } | 101 } |
71 | 102 |
72 /// Remembers [chunk] as containing the split that occurs right before an | 103 /// Remembers that [rule] is the [Rule] immediately following this positional |
73 /// argument in the list. | |
74 void beforeArgument(Chunk chunk) { | |
75 _arguments.add(chunk); | |
76 } | |
77 | |
78 /// Remembers that [rule] is the [NamedArgsRule] immediately following this | |
79 /// positional argument list. | 104 /// positional argument list. |
80 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) { |
81 _namedArgsRule = rule; | 110 _namedArgsRule = rule; |
82 } | 111 } |
83 | 112 |
84 /// 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 |
85 /// there are any splits in the positional arguments. Prevents things like: | 114 /// there are any splits in the positional arguments. Prevents things like: |
86 /// | 115 /// |
87 /// function( | 116 /// function( |
88 /// argument, | 117 /// argument, |
89 /// argument, named: argument); | 118 /// argument, named: argument); |
90 int constrain(int value, Rule other) { | 119 int constrain(int value, Rule other) { |
(...skipping 22 matching lines...) Expand all Loading... |
113 /// 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 |
114 /// internally without forcing a split before the argument. | 143 /// internally without forcing a split before the argument. |
115 final bool splitsOnInnerRules; | 144 final bool splitsOnInnerRules; |
116 | 145 |
117 /// Creates a new rule for a positional argument list. | 146 /// Creates a new rule for a positional argument list. |
118 /// | 147 /// |
119 /// 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 |
120 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will | 149 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will |
121 /// split before the argument if the argument itself contains a split. | 150 /// split before the argument if the argument itself contains a split. |
122 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) | 151 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) |
123 : super(collectionRule), | 152 : super(collectionRule, 0, 0), |
124 splitsOnInnerRules = | 153 splitsOnInnerRules = |
125 splitsOnInnerRules != null ? splitsOnInnerRules : false; | 154 splitsOnInnerRules != null ? splitsOnInnerRules : false; |
126 | 155 |
127 int constrain(int value, Rule other) { | 156 int constrain(int value, Rule other) { |
128 var constrained = super.constrain(value, other); | 157 var constrained = super.constrain(value, other); |
129 if (constrained != null) return constrained; | 158 if (constrained != null) return constrained; |
130 | 159 |
131 if (other != _collectionRule) return null; | 160 if (other != _collectionRule) return null; |
132 | 161 |
133 // 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. |
(...skipping 17 matching lines...) Expand all Loading... |
151 /// 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. |
152 /// 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 |
153 /// after the second argument and value 3 splits after the first. | 182 /// after the second argument and value 3 splits after the first. |
154 /// | 183 /// |
155 /// Then there is a value that splits before every argument. | 184 /// Then there is a value that splits before every argument. |
156 /// | 185 /// |
157 /// Finally, if there are collection arguments, there is another value that | 186 /// Finally, if there are collection arguments, there is another value that |
158 /// 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 |
159 /// before the collections, so that they can split internally. | 188 /// before the collections, so that they can split internally. |
160 class MultiplePositionalRule extends PositionalRule { | 189 class MultiplePositionalRule extends PositionalRule { |
161 /// The number of leading collection arguments. | |
162 /// | |
163 /// This and [_trailingCollections] cannot both be positive. If every | |
164 /// argument is a collection, this will be [_arguments.length] and | |
165 /// [_trailingCollections] will be 0. | |
166 final int _leadingCollections; | |
167 | |
168 /// The number of trailing collections. | |
169 /// | |
170 /// This and [_leadingCollections] cannot both be positive. | |
171 final int _trailingCollections; | |
172 | |
173 int get numValues { | 190 int get numValues { |
174 // Can split before any one argument, none, or all. | 191 // Can split before any one argument, none, or all. |
175 var result = 2 + _arguments.length; | 192 var result = 2 + _arguments.length; |
176 | 193 |
177 // 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 |
178 // "all" arguments: | 195 // "all" arguments: |
179 // | 196 // |
180 // - Split on just the non-collection arguments, and force the collection | 197 // - Split on just the non-collection arguments, and force the collection |
181 // arguments to split internally. | 198 // arguments to split internally. |
182 // - 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 |
183 // allow the collection arguments to split internally. | 200 // allow the collection arguments to split internally. |
184 if (_leadingCollections > 0 || _trailingCollections > 0) result++; | 201 if (_leadingCollections > 0 || _trailingCollections > 0) result++; |
185 | 202 |
186 return result; | 203 return result; |
187 } | 204 } |
188 | 205 |
189 MultiplePositionalRule( | 206 MultiplePositionalRule( |
190 Rule collectionRule, this._leadingCollections, this._trailingCollections) | 207 Rule collectionRule, int leadingCollections, int trailingCollections) |
191 : super(collectionRule); | 208 : super(collectionRule, leadingCollections, trailingCollections); |
192 | 209 |
193 String toString() => "*Pos${super.toString()}"; | 210 String toString() => "*Pos${super.toString()}"; |
194 | 211 |
195 bool isSplitAtValue(int value, Chunk chunk) { | 212 bool isSplitAtValue(int value, Chunk chunk) { |
196 // Split only before the first argument. Keep the entire argument list | 213 // Split only before the first argument. Keep the entire argument list |
197 // together on the next line. | 214 // together on the next line. |
198 if (value == 1) return chunk == _arguments.first; | 215 if (value == 1) return chunk == _arguments.first; |
199 | 216 |
200 // Split before a single argument. Try later arguments before earlier ones | 217 // Split before a single argument. Try later arguments before earlier ones |
201 // 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. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 if (value == _arguments.length + 1) return 1; | 283 if (value == _arguments.length + 1) return 1; |
267 | 284 |
268 // Split before all of the arguments, even the collections. We'll allow | 285 // Split before all of the arguments, even the collections. We'll allow |
269 // them to split but indent their bodies if they do. | 286 // them to split but indent their bodies if they do. |
270 return null; | 287 return null; |
271 } | 288 } |
272 } | 289 } |
273 | 290 |
274 /// 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: |
275 /// | 292 /// |
276 /// * 0: Do not split at all. | 293 /// * Do not split at all. |
277 /// * 1: Split only before first argument. | 294 /// * Split only before first argument. |
278 /// * 2: Split before all arguments, including the first. | 295 /// * Split before all arguments. |
279 class NamedRule extends ArgumentRule { | 296 class NamedRule extends ArgumentRule { |
280 /// The chunk prior to the first named argument. | |
281 Chunk _first; | |
282 | |
283 /// Whether any of the named arguments are collection literals. | |
284 final bool _containsCollections; | |
285 | |
286 int get numValues => 3; | 297 int get numValues => 3; |
287 | 298 |
288 NamedRule({bool containsCollections}) | 299 NamedRule( |
289 : _containsCollections = containsCollections ?? false; | 300 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 301 : super(collectionRule, leadingCollections, trailingCollections); |
290 | 302 |
291 void beforeArguments(Chunk chunk) { | 303 bool isSplitAtValue(int value, Chunk chunk) { |
292 assert(_first == null); | 304 // Move all arguments to the second line as a unit. |
293 _first = chunk; | 305 if (value == 1) return chunk == _arguments.first; |
| 306 |
| 307 // Otherwise, split before all arguments. |
| 308 return true; |
294 } | 309 } |
295 | 310 |
296 bool isSplitAtValue(int value, Chunk chunk) { | 311 int constrain(int value, Rule other) { |
297 // Only split before the first argument. | 312 var constrained = super.constrain(value, other); |
298 if (value == 1) return chunk == _first; | 313 if (constrained != null) return constrained; |
299 | 314 |
300 // Split before every argument. | 315 // Decide how to constrain the collection rule. |
301 return true; | 316 if (other != _collectionRule) return null; |
| 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 |
| 322 // If we aren't splitting any args, we can split the collection. |
| 323 if (value == Rule.unsplit) return null; |
| 324 |
| 325 // Split only before the first argument. Don't allow the collections to |
| 326 // split. |
| 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; |
302 } | 332 } |
303 | 333 |
304 String toString() => "Named${super.toString()}"; | 334 String toString() => "Named${super.toString()}"; |
305 } | 335 } |
OLD | NEW |