Chromium Code Reviews| 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 analyzer.src.task.inputs; | |
| 6 | |
| 7 import 'dart:collection'; | |
| 8 | |
| 9 import 'package:analyzer/task/model.dart'; | |
| 10 | |
| 11 /** | |
| 12 * A function that converts an arbitrary object into a [TaskInput]. This is | |
| 13 * used, for example, by a [ListBasedTaskInput] to create task inputs for each | |
| 14 * value in a list of values. | |
| 15 */ | |
| 16 typedef TaskInput<E> GenerateTaskInputs<E>(Object object); | |
| 17 | |
| 18 /** | |
| 19 * An input to an [AnalysisTask] that is computed by the following steps. First | |
| 20 * another (base) task input is used to compute a [List]-valued result. An input | |
| 21 * generator function is then used to map each element of that list to a task | |
| 22 * input. Finally, each of the task inputs are used to access analysis results, | |
| 23 * and the list of the analysis results is used as the input to the task. | |
| 24 */ | |
| 25 class ListBasedTaskInput<B, E> implements TaskInput<List<E>> { | |
| 26 /** | |
| 27 * The accessor used to access the list of elements being mapped. | |
| 28 */ | |
| 29 final TaskInput<B> baseAccessor; | |
| 30 | |
| 31 /** | |
| 32 * The function used to convert an element in the list returned by the | |
| 33 * [baseAccessor] to a task input. | |
| 34 */ | |
| 35 GenerateTaskInputs<E> generateTaskInputs; | |
| 36 | |
| 37 /** | |
| 38 * Initialize a result accessor to use the given [baseAccessor] to access a | |
| 39 * list of values that can be passed to the given [generateTaskInputs] to gene rate | |
| 40 * a list of task inputs that can be used to access the elements of the input | |
| 41 * being accessed. | |
| 42 */ | |
| 43 ListBasedTaskInput(this.baseAccessor, this.generateTaskInputs); | |
| 44 | |
| 45 @override | |
| 46 TaskInputBuilder<List<E>> createBuilder() => | |
| 47 new ListBasedTaskInputBuilder<B, E>(this); | |
| 48 } | |
| 49 | |
| 50 /** | |
| 51 * A [TaskInputBuilder] used to build an input based on a [ListBasedTaskInput]. | |
| 52 */ | |
| 53 class ListBasedTaskInputBuilder<B, E> implements TaskInputBuilder<List<E>> { | |
| 54 /** | |
| 55 * The input being built. | |
| 56 */ | |
| 57 final ListBasedTaskInput<B, E> input; | |
| 58 | |
| 59 /** | |
| 60 * The builder used to build the current result. | |
| 61 */ | |
| 62 TaskInputBuilder currentBuilder; | |
| 63 | |
| 64 /** | |
| 65 * The list of values computed by the [input]'s base accessor. | |
| 66 */ | |
| 67 List _baseList = null; | |
| 68 | |
| 69 /** | |
| 70 * The index in the [_baseList] of the value for which a value is currently | |
| 71 * being built. | |
| 72 */ | |
| 73 int _baseListIndex = -1; | |
| 74 | |
| 75 /** | |
| 76 * The list of values being built. | |
| 77 */ | |
| 78 List<E> _resultValue = null; | |
| 79 | |
| 80 /** | |
| 81 * Initialize a newly created task input builder that computes the result | |
| 82 * specified by the given [input]. | |
| 83 */ | |
| 84 ListBasedTaskInputBuilder(this.input); | |
| 85 | |
| 86 @override | |
| 87 ResultDescriptor get currentResult { | |
| 88 if (currentBuilder == null) { | |
| 89 return null; | |
| 90 } | |
| 91 return currentBuilder.currentResult; | |
| 92 } | |
| 93 | |
| 94 @override | |
| 95 AnalysisTarget get currentTarget { | |
| 96 if (currentBuilder == null) { | |
| 97 return null; | |
| 98 } | |
| 99 return currentBuilder.currentTarget; | |
| 100 } | |
| 101 | |
| 102 @override | |
| 103 void set currentValue(Object value) { | |
| 104 if (currentBuilder == null) { | |
| 105 throw new StateError( | |
| 106 'Cannot set the result value when there is no current result'); | |
| 107 } | |
| 108 currentBuilder.currentValue = value; | |
| 109 } | |
| 110 | |
| 111 @override | |
| 112 List<E> get inputValue { | |
| 113 if (currentBuilder != null || _resultValue == null) { | |
| 114 throw new StateError('Result value has not been created'); | |
| 115 } | |
| 116 return _resultValue; | |
| 117 } | |
| 118 | |
| 119 @override | |
| 120 bool moveNext() { | |
| 121 if (currentBuilder == null) { | |
| 122 if (_resultValue == null) { | |
| 123 // This is the first time moveNext has been invoked, so start by | |
| 124 // computing the list of values from which the results will be derived. | |
| 125 currentBuilder = input.baseAccessor.createBuilder(); | |
| 126 return currentBuilder.moveNext(); | |
| 127 } else { | |
| 128 // We have already computed all of the results, so just return false. | |
| 129 return false; | |
| 130 } | |
| 131 } | |
| 132 if (currentBuilder.moveNext()) { | |
| 133 return true; | |
| 134 } | |
| 135 if (_resultValue == null) { | |
| 136 // We have finished computing the list of values from which the results | |
| 137 // will be derived. | |
| 138 _baseList = currentBuilder.inputValue; | |
| 139 _baseListIndex = 0; | |
| 140 _resultValue = <E>[]; | |
| 141 } else { | |
| 142 // We have finished computing one of the elements in the result list. | |
| 143 _resultValue.add(currentBuilder.inputValue); | |
| 144 _baseListIndex++; | |
| 145 } | |
| 146 if (_baseListIndex >= _baseList.length) { | |
| 147 currentBuilder = null; | |
| 148 return false; | |
| 149 } | |
| 150 currentBuilder = | |
| 151 input.generateTaskInputs(_baseList[_baseListIndex]).createBuilder(); | |
| 152 return currentBuilder.moveNext(); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 /** | |
| 157 * An input to an [AnalysisTask] that is computed by accessing a single result | |
| 158 * defined on a single target. | |
| 159 */ | |
| 160 class SimpleTaskInput<V> implements TaskInput<V> { | |
| 161 /** | |
| 162 * The target on which the result is defined. | |
| 163 */ | |
| 164 final AnalysisTarget target; | |
| 165 | |
| 166 /** | |
| 167 * The result to be accessed. | |
| 168 */ | |
| 169 final ResultDescriptor<V> result; | |
| 170 | |
| 171 /** | |
| 172 * Initialize a newly created task input that computes the input by accessing | |
| 173 * the given [result] associated with the given [target]. | |
| 174 */ | |
| 175 SimpleTaskInput(this.target, this.result); | |
| 176 | |
| 177 @override | |
| 178 TaskInputBuilder<V> createBuilder() => new SimpleTaskInputBuilder<V>(this); | |
| 179 } | |
| 180 | |
| 181 /** | |
| 182 * A [TaskInputBuilder] used to build an input based on a [SimpleTaskInput]. | |
| 183 */ | |
| 184 class SimpleTaskInputBuilder<V> implements TaskInputBuilder<V> { | |
| 185 /** | |
| 186 * The state value indicating that the builder is positioned before the single result. | |
| 187 */ | |
| 188 static const _BEFORE = -1; | |
| 189 | |
| 190 /** | |
| 191 * The state value indicating that the builder is positioned at the single res ult. | |
| 192 */ | |
| 193 static const _AT = 0; | |
| 194 | |
| 195 /** | |
| 196 * The state value indicating that the builder is positioned before the single result. | |
|
scheglov
2015/01/21 14:50:47
"after the single result"
Brian Wilkerson
2015/01/26 04:54:51
Done
| |
| 197 */ | |
| 198 static const _AFTER = 1; | |
| 199 | |
| 200 /** | |
| 201 * The input being built. | |
| 202 */ | |
| 203 final SimpleTaskInput<V> input; | |
| 204 | |
| 205 /** | |
| 206 * The value of the input being built. | |
| 207 */ | |
| 208 V _resultValue = null; | |
| 209 | |
| 210 /** | |
| 211 * The state of the builder. | |
| 212 */ | |
| 213 int _state = _BEFORE; | |
| 214 | |
| 215 /** | |
| 216 * A flag indicating whether the result value was explicitly set. | |
| 217 */ | |
| 218 bool _resultSet = false; | |
| 219 | |
| 220 /** | |
| 221 * Initialize a newly created task input builder that computes the result | |
| 222 * specified by the given [input]. | |
| 223 */ | |
| 224 SimpleTaskInputBuilder(this.input); | |
| 225 | |
| 226 @override | |
| 227 ResultDescriptor get currentResult => _state == _AT ? input.result : null; | |
| 228 | |
| 229 @override | |
| 230 AnalysisTarget get currentTarget => _state == _AT ? input.target : null; | |
| 231 | |
| 232 @override | |
| 233 void set currentValue(Object value) { | |
| 234 if (_state != _AT) { | |
| 235 throw new StateError( | |
| 236 'Cannot set the result value when there is no current result'); | |
| 237 } | |
| 238 _resultValue = value as V; | |
| 239 _resultSet = true; | |
| 240 } | |
| 241 | |
| 242 @override | |
| 243 V get inputValue { | |
| 244 if (_state != _AFTER) { | |
| 245 throw new StateError('Result value has not been created'); | |
| 246 } | |
| 247 return _resultValue; | |
| 248 } | |
| 249 | |
| 250 @override | |
| 251 bool moveNext() { | |
| 252 if (_state == _BEFORE) { | |
| 253 _state = _AT; | |
| 254 return true; | |
| 255 } else { | |
| 256 if (!_resultSet) { | |
| 257 throw new StateError( | |
| 258 'The value of the current result must be set before moving to the ne xt result.'); | |
| 259 } | |
| 260 _state = _AFTER; | |
| 261 return false; | |
| 262 } | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 /** | |
| 267 * A [TaskInputBuilder] used to build an input based on one or more other task | |
| 268 * inputs. The task inputs to be built are specified by a table mapping the name | |
| 269 * of the input to the task used to access the input's value. | |
| 270 */ | |
| 271 class TopLevelTaskInputBuilder implements TaskInputBuilder<Map<String, Object>> | |
| 272 { | |
| 273 /** | |
| 274 * The descriptors describing the inputs to be built. | |
| 275 */ | |
| 276 final Map<String, TaskInput> inputDescriptors; | |
| 277 | |
| 278 /** | |
| 279 * The names of the inputs. There are the keys from the [inputDescriptors] in | |
| 280 * an indexable form. | |
| 281 */ | |
| 282 List<String> inputNames; | |
| 283 | |
| 284 /** | |
| 285 * The index of the input name associated with the current result and target. | |
| 286 */ | |
| 287 int nameIndex = -1; | |
| 288 | |
| 289 /** | |
| 290 * The builder used to build the current result. | |
| 291 */ | |
| 292 TaskInputBuilder currentBuilder; | |
| 293 | |
| 294 /** | |
| 295 * The inputs that are being or have been built. The map will be incomplete | |
| 296 * unless the method [moveNext] returns `false`. | |
| 297 */ | |
| 298 final Map<String, Object> inputs = new HashMap<String, Object>(); | |
| 299 | |
| 300 /** | |
| 301 * Initialize a newly created task input builder to build the inputs described | |
| 302 * by the given [inputDescriptors]. | |
| 303 */ | |
| 304 TopLevelTaskInputBuilder(this.inputDescriptors) { | |
| 305 inputNames = inputDescriptors.keys.toList(); | |
| 306 } | |
| 307 | |
| 308 @override | |
| 309 ResultDescriptor get currentResult { | |
| 310 if (currentBuilder == null) { | |
| 311 return null; | |
| 312 } | |
| 313 return currentBuilder.currentResult; | |
| 314 } | |
| 315 | |
| 316 @override | |
| 317 AnalysisTarget get currentTarget { | |
| 318 if (currentBuilder == null) { | |
| 319 return null; | |
| 320 } | |
| 321 return currentBuilder.currentTarget; | |
| 322 } | |
| 323 | |
| 324 @override | |
| 325 void set currentValue(Object value) { | |
| 326 if (currentBuilder == null) { | |
| 327 throw new StateError( | |
| 328 'Cannot set the result value when there is no current result'); | |
| 329 } | |
| 330 currentBuilder.currentValue = value; | |
| 331 } | |
| 332 | |
| 333 @override | |
| 334 Map<String, Object> get inputValue { | |
| 335 if (nameIndex < inputNames.length) { | |
| 336 throw new StateError('Result value has not been created'); | |
| 337 } | |
| 338 return inputs; | |
| 339 } | |
| 340 | |
| 341 /** | |
| 342 * Assuming that there is a current input, return its name. | |
| 343 */ | |
| 344 String get _currentName => inputNames[nameIndex]; | |
| 345 | |
| 346 @override | |
| 347 bool moveNext() { | |
| 348 if (nameIndex >= inputNames.length) { | |
| 349 // We have already computed all of the results, so just return false. | |
| 350 return false; | |
| 351 } | |
| 352 if (nameIndex < 0) { | |
| 353 // This is the first time moveNext has been invoked, so we just determine | |
| 354 // whether there are any results to be computed. | |
| 355 nameIndex = 0; | |
| 356 } else { | |
| 357 if (currentBuilder.moveNext()) { | |
| 358 // We are still working on building the value associated with the | |
| 359 // current name. | |
| 360 return true; | |
| 361 } | |
| 362 inputs[_currentName] = currentBuilder.inputValue; | |
| 363 nameIndex++; | |
| 364 } | |
| 365 if (nameIndex >= inputNames.length) { | |
| 366 // There is no next value, so we're done. | |
| 367 return false; | |
| 368 } | |
| 369 currentBuilder = inputDescriptors[_currentName].createBuilder(); | |
| 370 // NOTE: This assumes that every builder will require at least one result | |
| 371 // value to be created. If that assumption is every broken, this method will | |
| 372 // need to be changed to advance until we find a builder that does require | |
| 373 // a result to be computed (or run out of builders). | |
| 374 return currentBuilder.moveNext(); | |
| 375 } | |
| 376 } | |
| OLD | NEW |