| 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 |