| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dart_style.src.rule.argument; | |
| 6 | |
| 7 import '../chunk.dart'; | |
| 8 import 'rule.dart'; | |
| 9 | |
| 10 /// Base class for a rule that handles argument or parameter lists. | |
| 11 abstract class ArgumentRule extends Rule { | |
| 12 /// The rule used to split collections in the argument list, if any. | |
| 13 final Rule _collectionRule; | |
| 14 | |
| 15 /// If true, then inner rules that are written will force this rule to split. | |
| 16 /// | |
| 17 /// Temporarily disabled while writing collectio arguments so that they can be | |
| 18 /// multi-line without forcing the whole argument list to split. | |
| 19 bool _trackInnerRules = true; | |
| 20 | |
| 21 /// Don't split when an inner collection rule splits. | |
| 22 bool get splitsOnInnerRules => _trackInnerRules; | |
| 23 | |
| 24 /// Creates a new rule for a positional argument list. | |
| 25 /// | |
| 26 /// If [_collectionRule] is given, it is the rule used to split the | |
| 27 /// collections in the list. | |
| 28 ArgumentRule(this._collectionRule); | |
| 29 | |
| 30 /// Called before a collection argument is written. | |
| 31 /// | |
| 32 /// Disables tracking inner rules while a collection argument is written. | |
| 33 void beforeCollection() { | |
| 34 assert(_trackInnerRules == true); | |
| 35 _trackInnerRules = false; | |
| 36 } | |
| 37 | |
| 38 /// Called after a collection argument is complete. | |
| 39 /// | |
| 40 /// Re-enables tracking inner rules. | |
| 41 void afterCollection() { | |
| 42 assert(_trackInnerRules == false); | |
| 43 _trackInnerRules = true; | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 /// Base class for a rule for handling positional argument lists. | |
| 48 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 | |
| 53 /// be their rule. | |
| 54 Rule _namedArgsRule; | |
| 55 | |
| 56 /// Creates a new rule for a positional argument list. | |
| 57 /// | |
| 58 /// If [collectionRule] is given, it is the rule used to split the collection | |
| 59 /// arguments in the list. | |
| 60 PositionalRule(Rule collectionRule) : super(collectionRule); | |
| 61 | |
| 62 /// Remembers [chunk] as containing the split that occurs right before an | |
| 63 /// argument in the list. | |
| 64 void beforeArgument(Chunk chunk) { | |
| 65 _arguments.add(chunk); | |
| 66 } | |
| 67 | |
| 68 /// Remembers that [rule] is the [NamedArgsRule] immediately following this | |
| 69 /// positional argument list. | |
| 70 void setNamedArgsRule(NamedRule rule) { | |
| 71 _namedArgsRule = rule; | |
| 72 } | |
| 73 | |
| 74 /// 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: | |
| 76 /// | |
| 77 /// function( | |
| 78 /// argument, | |
| 79 /// argument, named: argument); | |
| 80 int constrain(int value, Rule other) { | |
| 81 var constrained = super.constrain(value, other); | |
| 82 if (constrained != null) return constrained; | |
| 83 | |
| 84 // Handle the relationship between the positional and named args. | |
| 85 if (other == _namedArgsRule) { | |
| 86 // If the positional args are one-per-line, the named args are too. | |
| 87 if (value == fullySplitValue) return _namedArgsRule.fullySplitValue; | |
| 88 | |
| 89 // Otherwise, if there is any split in the positional arguments, don't | |
| 90 // allow the named arguments on the same line as them. | |
| 91 if (value != 0) return -1; | |
| 92 } | |
| 93 | |
| 94 return null; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 /// Split rule for a call with a single positional argument (which may or may | |
| 99 /// not be a collection argument.) | |
| 100 class SinglePositionalRule extends PositionalRule { | |
| 101 int get numValues => 2; | |
| 102 | |
| 103 /// If there is only a single non-collection argument, allow it to split | |
| 104 /// internally without forcing a split before the argument. | |
| 105 final bool splitsOnInnerRules; | |
| 106 | |
| 107 bool hack = false; | |
| 108 | |
| 109 /// Creates a new rule for a positional argument list. | |
| 110 /// | |
| 111 /// If [collectionRule] is given, it is the rule used to split the | |
| 112 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will | |
| 113 /// split before the argument if the argument itself contains a split. | |
| 114 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) | |
| 115 : super(collectionRule), | |
| 116 splitsOnInnerRules = | |
| 117 splitsOnInnerRules != null ? splitsOnInnerRules : false; | |
| 118 | |
| 119 bool isSplit(int value, Chunk chunk) => value == 1; | |
| 120 | |
| 121 int constrain(int value, Rule other) { | |
| 122 var constrained = super.constrain(value, other); | |
| 123 if (constrained != null) return constrained; | |
| 124 | |
| 125 if (other != _collectionRule) return null; | |
| 126 | |
| 127 // If we aren't splitting any args, we can split the collection. | |
| 128 if (value == 0) return null; | |
| 129 | |
| 130 // We are splitting before a collection, so don't let it split internally. | |
| 131 return 0; | |
| 132 } | |
| 133 | |
| 134 String toString() => "1Pos${super.toString()}"; | |
| 135 } | |
| 136 | |
| 137 /// Split rule for a call with more than one positional argument. | |
| 138 /// | |
| 139 /// 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: | |
| 141 /// | |
| 142 /// * 0: Do not split at all. | |
| 143 /// * 1: Split only before the first argument. | |
| 144 /// | |
| 145 /// 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 | |
| 147 /// after the second argument and value 3 splits after the first. | |
| 148 /// | |
| 149 /// Then there is a value that splits before every argument. | |
| 150 /// | |
| 151 /// Finally, if there are collection arguments, there is another value that | |
| 152 /// splits before all of the non-collection arguments, but does not split | |
| 153 /// before the collections, so that they can split internally. | |
| 154 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 { | |
| 168 // Can split before any one argument, none, or all. | |
| 169 var result = 2 + _arguments.length; | |
| 170 | |
| 171 // When there are collection arguments, there are two ways we can split on | |
| 172 // "all" arguments: | |
| 173 // | |
| 174 // - Split on just the non-collection arguments, and force the collection | |
| 175 // arguments to split internally. | |
| 176 // - Split on all of them including the collection arguments, and do not | |
| 177 // allow the collection arguments to split internally. | |
| 178 if (_leadingCollections > 0 || _trailingCollections > 0) result++; | |
| 179 | |
| 180 return result; | |
| 181 } | |
| 182 | |
| 183 MultiplePositionalRule( | |
| 184 Rule collectionRule, this._leadingCollections, this._trailingCollections) | |
| 185 : super(collectionRule); | |
| 186 | |
| 187 String toString() => "*Pos${super.toString()}"; | |
| 188 | |
| 189 bool isSplit(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 | |
| 194 // together on the next line. | |
| 195 if (value == 1) return chunk == _arguments.first; | |
| 196 | |
| 197 // Split before a single argument. Try later arguments before earlier ones | |
| 198 // to try to keep as much on the first line as possible. | |
| 199 if (value <= _arguments.length) { | |
| 200 var argument = _arguments.length - value + 1; | |
| 201 return chunk == _arguments[argument]; | |
| 202 } | |
| 203 | |
| 204 // Only split before the non-collection arguments. | |
| 205 if (value == _arguments.length + 1) { | |
| 206 for (var i = 0; i < _leadingCollections; i++) { | |
| 207 if (chunk == _arguments[i]) return false; | |
| 208 } | |
| 209 | |
| 210 for (var i = _arguments.length - _trailingCollections; | |
| 211 i < _arguments.length; | |
| 212 i++) { | |
| 213 if (chunk == _arguments[i]) return false; | |
| 214 } | |
| 215 | |
| 216 return true; | |
| 217 } | |
| 218 | |
| 219 // Split before all of the arguments, even the collections. | |
| 220 return true; | |
| 221 } | |
| 222 | |
| 223 int constrain(int value, Rule other) { | |
| 224 var constrained = super.constrain(value, other); | |
| 225 if (constrained != null) return constrained; | |
| 226 | |
| 227 if (other != _collectionRule) return null; | |
| 228 | |
| 229 // If we aren't splitting any args, we can split the collection. | |
| 230 if (value == 0) return null; | |
| 231 | |
| 232 // Split only before the first argument. | |
| 233 if (value == 1) { | |
| 234 if (_leadingCollections > 0) { | |
| 235 // We are splitting before a collection, so don't let it split | |
| 236 // internally. | |
| 237 return 0; | |
| 238 } else { | |
| 239 // The split is outside of the collections so they can split or not. | |
| 240 return null; | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 // Split before a single argument. If it's in the middle of the collection | |
| 245 // arguments, don't allow them to split. | |
| 246 if (value <= _arguments.length) { | |
| 247 var argument = _arguments.length - value + 1; | |
| 248 if (argument < _leadingCollections) return 0; | |
| 249 if (argument >= _arguments.length - _trailingCollections) return 0; | |
| 250 | |
| 251 return null; | |
| 252 } | |
| 253 | |
| 254 // 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. | |
| 256 if (value == _arguments.length + 1) return 1; | |
| 257 | |
| 258 // Split before all of the arguments, even the collection, so don't let | |
| 259 // them split. | |
| 260 return 0; | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 /// Splitting rule for a list of named arguments or parameters. Its values mean: | |
| 265 /// | |
| 266 /// * 0: Do not split at all. | |
| 267 /// * 1: Split only before first argument. | |
| 268 /// * 2: Split before all arguments, including the first. | |
| 269 class NamedRule extends ArgumentRule { | |
| 270 /// The chunk prior to the first named argument. | |
| 271 Chunk _first; | |
| 272 | |
| 273 int get numValues => 3; | |
| 274 | |
| 275 NamedRule(Rule collectionRule) : super(collectionRule); | |
| 276 | |
| 277 void beforeArguments(Chunk chunk) { | |
| 278 assert(_first == null); | |
| 279 _first = chunk; | |
| 280 } | |
| 281 | |
| 282 bool isSplit(int value, Chunk chunk) { | |
| 283 switch (value) { | |
| 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 } | |
| 294 | |
| 295 int constrain(int value, Rule other) { | |
| 296 var constrained = super.constrain(value, other); | |
| 297 if (constrained != null) return constrained; | |
| 298 | |
| 299 if (other != _collectionRule) return null; | |
| 300 | |
| 301 // If we aren't splitting any args, we can split the collection. | |
| 302 if (value == 0) return null; | |
| 303 | |
| 304 // Split before all of the arguments, even the collections, so don't let | |
| 305 // them split. | |
| 306 return 0; | |
| 307 } | |
| 308 | |
| 309 String toString() => "Named${super.toString()}"; | |
| 310 } | |
| OLD | NEW |