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