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