Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: third_party/pkg/angular/lib/change_detection/watch_group.dart

Issue 256553002: Revert "Update all Angular libs (run update_all.sh)." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 library angular.watch_group; 1 library angular.watch_group;
2 2
3 import 'dart:mirrors';
3 import 'package:angular/change_detection/change_detection.dart'; 4 import 'package:angular/change_detection/change_detection.dart';
4 5
5 part 'linked_list.dart'; 6 part 'linked_list.dart';
6 part 'ast.dart'; 7 part 'ast.dart';
7 part 'prototype_map.dart'; 8 part 'prototype_map.dart';
8 9
9 /** 10 typedef ReactionFn(value, previousValue);
10 * A function that is notified of changes to the model. 11 typedef ChangeLog(String expression, current, previous);
11 *
12 * ReactionFn is a function implemented by the developer that executes when a ch ange is detected
13 * in a watched expression.
14 *
15 * * [value]: The current value of the watched expression.
16 * * [previousValue]: The previous value of the watched expression.
17 *
18 * If the expression is watching a collection (a list or a map), then [value] is wrapped in
19 * a [CollectionChangeItem] that lists all the changes.
20 */
21 typedef void ReactionFn(value, previousValue);
22 typedef void ChangeLog(String expression, current, previous);
23 12
24 /** 13 /**
25 * Extend this class if you wish to pretend to be a function, but you don't know 14 * Extend this class if you wish to pretend to be a function, but you don't know
26 * number of arguments with which the function will get called with. 15 * number of arguments with which the function will get called.
27 */ 16 */
28 abstract class FunctionApply { 17 abstract class FunctionApply {
29 // dartbug.com/16401 18 // dartbug.com/16401
30 // dynamic call() { throw new StateError('Use apply()'); } 19 // dynamic call() { throw new StateError('Use apply()'); }
31 dynamic apply(List arguments); 20 dynamic apply(List arguments);
32 } 21 }
33 22
34 /** 23 /**
35 * [WatchGroup] is a logical grouping of a set of watches. [WatchGroup]s are 24 * [WatchGroup] is a logical grouping of a set of watches. [WatchGroup]s are
36 * organized into a hierarchical tree parent-children configuration. 25 * organized into a hierarchical tree parent-children configuration.
(...skipping 23 matching lines...) Expand all
60 /// STATS: Number of field watchers which are in use. 49 /// STATS: Number of field watchers which are in use.
61 int _fieldCost = 0; 50 int _fieldCost = 0;
62 int _collectionCost = 0; 51 int _collectionCost = 0;
63 int _evalCost = 0; 52 int _evalCost = 0;
64 53
65 /// STATS: Number of field watchers which are in use including child [WatchGro up]s. 54 /// STATS: Number of field watchers which are in use including child [WatchGro up]s.
66 int get fieldCost => _fieldCost; 55 int get fieldCost => _fieldCost;
67 int get totalFieldCost { 56 int get totalFieldCost {
68 var cost = _fieldCost; 57 var cost = _fieldCost;
69 WatchGroup group = _watchGroupHead; 58 WatchGroup group = _watchGroupHead;
70 while (group != null) { 59 while(group != null) {
71 cost += group.totalFieldCost; 60 cost += group.totalFieldCost;
72 group = group._nextWatchGroup; 61 group = group._nextWatchGroup;
73 } 62 }
74 return cost; 63 return cost;
75 } 64 }
76 65
77 /// STATS: Number of collection watchers which are in use including child [Wat chGroup]s. 66 /// STATS: Number of collection watchers which are in use including child [Wat chGroup]s.
78 int get collectionCost => _collectionCost; 67 int get collectionCost => _collectionCost;
79 int get totalCollectionCost { 68 int get totalCollectionCost {
80 var cost = _collectionCost; 69 var cost = _collectionCost;
81 WatchGroup group = _watchGroupHead; 70 WatchGroup group = _watchGroupHead;
82 while (group != null) { 71 while(group != null) {
83 cost += group.totalCollectionCost; 72 cost += group.totalCollectionCost;
84 group = group._nextWatchGroup; 73 group = group._nextWatchGroup;
85 } 74 }
86 return cost; 75 return cost;
87 } 76 }
88 77
89 /// STATS: Number of invocation watchers (closures/methods) which are in use. 78 /// STATS: Number of invocation watchers (closures/methods) which are in use.
90 int get evalCost => _evalCost; 79 int get evalCost => _evalCost;
91 80
92 /// STATS: Number of invocation watchers which are in use including child [Wat chGroup]s. 81 /// STATS: Number of invocation watchers which are in use including child [Wat chGroup]s.
93 int get totalEvalCost { 82 int get totalEvalCost {
94 var cost = _evalCost; 83 var cost = _evalCost;
95 WatchGroup group = _watchGroupHead; 84 WatchGroup group = _watchGroupHead;
96 while (group != null) { 85 while(group != null) {
97 cost += group.evalCost; 86 cost += group.evalCost;
98 group = group._nextWatchGroup; 87 group = group._nextWatchGroup;
99 } 88 }
100 return cost; 89 return cost;
101 } 90 }
102 91
103 int _nextChildId = 0; 92 int _nextChildId = 0;
104 _EvalWatchRecord _evalWatchHead, _evalWatchTail; 93 _EvalWatchRecord _evalWatchHead, _evalWatchTail;
105 /// Pointer for creating tree of [WatchGroup]s. 94 /// Pointer for creating tree of [WatchGroup]s.
95 WatchGroup _watchGroupHead, _watchGroupTail, _previousWatchGroup,
96 _nextWatchGroup;
106 WatchGroup _parentWatchGroup; 97 WatchGroup _parentWatchGroup;
107 WatchGroup _watchGroupHead, _watchGroupTail;
108 WatchGroup _prevWatchGroup, _nextWatchGroup;
109 98
110 WatchGroup._child(_parentWatchGroup, this._changeDetector, this.context, 99 WatchGroup._child(_parentWatchGroup, this._changeDetector, this.context,
111 this._cache, this._rootGroup) 100 this._cache, this._rootGroup)
112 : _parentWatchGroup = _parentWatchGroup, 101 : _parentWatchGroup = _parentWatchGroup,
113 id = '${_parentWatchGroup.id}.${_parentWatchGroup._nextChildId++}' 102 id = '${_parentWatchGroup.id}.${_parentWatchGroup._nextChildId++}'
114 { 103 {
115 _marker.watchGrp = this; 104 _marker.watchGrp = this;
116 _evalWatchTail = _evalWatchHead = _marker; 105 _evalWatchTail = _evalWatchHead = _marker;
117 } 106 }
118 107
119 WatchGroup._root(this._changeDetector, this.context) 108 WatchGroup._root(this._changeDetector, this.context)
120 : id = '', 109 : id = '',
121 _rootGroup = null, 110 _rootGroup = null,
122 _parentWatchGroup = null, 111 _parentWatchGroup = null,
123 _cache = new Map<String, WatchRecord<_Handler>>() 112 _cache = new Map<String, WatchRecord<_Handler>>()
124 { 113 {
125 _marker.watchGrp = this; 114 _marker.watchGrp = this;
126 _evalWatchTail = _evalWatchHead = _marker; 115 _evalWatchTail = _evalWatchHead = _marker;
127 } 116 }
128 117
129 get isAttached { 118 get isAttached {
130 var group = this; 119 var group = this;
131 var root = _rootGroup; 120 var root = _rootGroup;
132 while (group != null) { 121 while(group != null) {
133 if (group == root){ 122 if (group == root){
134 return true; 123 return true;
135 } 124 }
136 group = group._parentWatchGroup; 125 group = group._parentWatchGroup;
137 } 126 }
138 return false; 127 return false;
139 } 128 }
140 129
141 Watch watch(AST expression, ReactionFn reactionFn) { 130 Watch watch(AST expression, ReactionFn reactionFn) {
142 WatchRecord<_Handler> watchRecord = 131 WatchRecord<_Handler> watchRecord =
143 _cache.putIfAbsent(expression.expression, 132 _cache.putIfAbsent(expression.expression,
144 () => expression.setupWatch(this)); 133 () => expression.setupWatch(this));
145 return watchRecord.handler.addReactionFn(reactionFn); 134 return watchRecord.handler.addReactionFn(reactionFn);
146 } 135 }
147 136
148 /** 137 /**
149 * Watch a [name] field on [lhs] represented by [expression]. 138 * Watch a [name] field on [lhs] represented by [expression].
150 * 139 *
151 * - [name] the field to watch. 140 * - [name] the field to watch.
152 * - [lhs] left-hand-side of the field. 141 * - [lhs] left-hand-side of the field.
153 */ 142 */
154 WatchRecord<_Handler> addFieldWatch(AST lhs, String name, String expression) { 143 WatchRecord<_Handler> addFieldWatch(AST lhs, String name, String expression) {
155 var fieldHandler = new _FieldHandler(this, expression); 144 var fieldHandler = new _FieldHandler(this, expression);
156 145
157 // Create a Record for the current field and assign the change record 146 // Create a ChangeRecord for the current field and assign the change record
158 // to the handler. 147 // to the handler.
159 var watchRecord = _changeDetector.watch(null, name, fieldHandler); 148 var watchRecord = _changeDetector.watch(null, name, fieldHandler);
160 _fieldCost++; 149 _fieldCost++;
161 fieldHandler.watchRecord = watchRecord; 150 fieldHandler.watchRecord = watchRecord;
162 151
163 WatchRecord<_Handler> lhsWR = _cache.putIfAbsent(lhs.expression, 152 WatchRecord<_Handler> lhsWR = _cache.putIfAbsent(lhs.expression,
164 () => lhs.setupWatch(this)); 153 () => lhs.setupWatch(this));
165 154
166 // We set a field forwarding handler on LHS. This will allow the change 155 // We set a field forwarding handler on LHS. This will allow the change
167 // objects to propagate to the current WatchRecord. 156 // objects to propagate to the current WatchRecord.
(...skipping 20 matching lines...) Expand all
188 collectionHandler.acceptValue(astWR.currentValue); 177 collectionHandler.acceptValue(astWR.currentValue);
189 return watchRecord; 178 return watchRecord;
190 } 179 }
191 180
192 /** 181 /**
193 * Watch a [fn] function represented by an [expression]. 182 * Watch a [fn] function represented by an [expression].
194 * 183 *
195 * - [fn] function to evaluate. 184 * - [fn] function to evaluate.
196 * - [argsAST] list of [AST]es which represent arguments passed to function. 185 * - [argsAST] list of [AST]es which represent arguments passed to function.
197 * - [expression] normalized expression used for caching. 186 * - [expression] normalized expression used for caching.
198 * - [isPure] A pure function is one which holds no internal state. This impli es that the
199 * function is idempotent.
200 */ 187 */
201 _EvalWatchRecord addFunctionWatch(/* dartbug.com/16401 Function */ fn, List<AS T> argsAST, 188 _EvalWatchRecord addFunctionWatch(/* dartbug.com/16401 Function */ fn, List<AS T> argsAST,
202 Map<Symbol, AST> namedArgsAST, 189 String expression) =>
203 String expression, bool isPure) => 190 _addEvalWatch(null, fn, null, argsAST, expression);
204 _addEvalWatch(null, fn, null, argsAST, namedArgsAST, expression, isPure);
205 191
206 /** 192 /**
207 * Watch a method [name]ed represented by an [expression]. 193 * Watch a method [name]ed represented by an [expression].
208 * 194 *
209 * - [lhs] left-hand-side of the method. 195 * - [lhs] left-hand-side of the method.
210 * - [name] name of the method. 196 * - [name] name of the method.
211 * - [argsAST] list of [AST]es which represent arguments passed to method. 197 * - [argsAST] list of [AST]es which represent arguments passed to method.
212 * - [expression] normalized expression used for caching. 198 * - [expression] normalized expression used for caching.
213 */ 199 */
214 _EvalWatchRecord addMethodWatch(AST lhs, String name, List<AST> argsAST, 200 _EvalWatchRecord addMethodWatch(AST lhs, String name, List<AST> argsAST,
215 Map<Symbol, AST> namedArgsAST,
216 String expression) => 201 String expression) =>
217 _addEvalWatch(lhs, null, name, argsAST, namedArgsAST, expression, false); 202 _addEvalWatch(lhs, null, name, argsAST, expression);
218 203
219 204
220 205
221 _EvalWatchRecord _addEvalWatch(AST lhsAST, /* dartbug.com/16401 Function */ fn , String name, 206 _EvalWatchRecord _addEvalWatch(AST lhsAST, /* dartbug.com/16401 Function */ fn , String name,
222 List<AST> argsAST, 207 List<AST> argsAST, String expression) {
223 Map<Symbol, AST> namedArgsAST,
224 String expression, bool isPure) {
225 _InvokeHandler invokeHandler = new _InvokeHandler(this, expression); 208 _InvokeHandler invokeHandler = new _InvokeHandler(this, expression);
226 var evalWatchRecord = new _EvalWatchRecord( 209 var evalWatchRecord = new _EvalWatchRecord(this, invokeHandler, fn, name,
227 _rootGroup._fieldGetterFactory, this, invokeHandler, fn, name, 210 argsAST.length);
228 argsAST.length, isPure);
229 invokeHandler.watchRecord = evalWatchRecord; 211 invokeHandler.watchRecord = evalWatchRecord;
230 212
231 if (lhsAST != null) { 213 if (lhsAST != null) {
232 var lhsWR = _cache.putIfAbsent(lhsAST.expression, 214 var lhsWR = _cache.putIfAbsent(lhsAST.expression,
233 () => lhsAST.setupWatch(this)); 215 () => lhsAST.setupWatch(this));
234 lhsWR.handler.addForwardHandler(invokeHandler); 216 lhsWR.handler.addForwardHandler(invokeHandler);
235 invokeHandler.acceptValue(lhsWR.currentValue); 217 invokeHandler.acceptValue(lhsWR.currentValue);
236 } 218 }
237 219
238 // Convert the args from AST to WatchRecords 220 // Convert the args from AST to WatchRecords
239 Iterable<WatchRecord<_Handler>> records = argsAST.map((ast) => 221 var i = 0;
240 _cache.putIfAbsent(ast.expression, () => ast.setupWatch(this))); 222 argsAST.
241 int i = 0; 223 map((ast) => _cache.putIfAbsent(ast.expression,
242 records.forEach((WatchRecord<_Handler> record) { 224 () => ast.setupWatch(this))).forEach((WatchRecord<_Handler> record) {
243 _ArgHandler handler = new _PositionalArgHandler(this, evalWatchRecord, i++ ); 225 var argHandler = new _ArgHandler(this, evalWatchRecord, i++);
244 _ArgHandlerList._add(invokeHandler, handler); 226 _ArgHandlerList._add(invokeHandler, argHandler);
245 record.handler.addForwardHandler(handler); 227 record.handler.addForwardHandler(argHandler);
246 handler.acceptValue(record.currentValue); 228 argHandler.acceptValue(record.currentValue);
247 });
248
249 namedArgsAST.forEach((Symbol name, AST ast) {
250 WatchRecord<_Handler> record = _cache.putIfAbsent(ast.expression,
251 () => ast.setupWatch(this));
252 _ArgHandler handler = new _NamedArgHandler(this, evalWatchRecord, name);
253 _ArgHandlerList._add(invokeHandler, handler);
254 record.handler.addForwardHandler(handler);
255 handler.acceptValue(record.currentValue);
256 }); 229 });
257 230
258 // Must be done last 231 // Must be done last
259 _EvalWatchList._add(this, evalWatchRecord); 232 _EvalWatchList._add(this, evalWatchRecord);
260 _evalCost++; 233 _evalCost++;
261 if (_rootGroup.isInsideInvokeDirty) { 234
262 // This check means that we are inside invoke reaction function.
263 // Registering a new EvalWatch at this point will not run the
264 // .check() on it which means it will not be processed, but its
265 // reaction function will be run with null. So we process it manually.
266 evalWatchRecord.check();
267 }
268 return evalWatchRecord; 235 return evalWatchRecord;
269 } 236 }
270 237
271 WatchGroup get _childWatchGroupTail { 238 WatchGroup get _childWatchGroupTail {
272 var tail = this, nextTail; 239 var tail = this, nextTail;
273 while ((nextTail = tail._watchGroupTail) != null) { 240 while ((nextTail = tail._watchGroupTail) != null) {
274 tail = nextTail; 241 tail = nextTail;
275 } 242 }
276 return tail; 243 return tail;
277 } 244 }
278 245
279 /** 246 /**
280 * Create a new child [WatchGroup]. 247 * Create a new child [WatchGroup].
281 * 248 *
282 * - [context] if present the the child [WatchGroup] expressions will evaluate 249 * - [context] if present the the child [WatchGroup] expressions will evaluate
283 * against the new [context]. If not present than child expressions will 250 * against the new [context]. If not present than child expressions will
284 * evaluate on same context allowing the reuse of the expression cache. 251 * evaluate on same context allowing the reuse of the expression cache.
285 */ 252 */
286 WatchGroup newGroup([Object context]) { 253 WatchGroup newGroup([Object context]) {
287 _EvalWatchRecord prev = _childWatchGroupTail._evalWatchTail; 254 _EvalWatchRecord prev = _childWatchGroupTail._evalWatchTail;
288 _EvalWatchRecord next = prev._nextEvalWatch; 255 _EvalWatchRecord next = prev._nextEvalWatch;
289 var childGroup = new WatchGroup._child( 256 var childGroup = new WatchGroup._child(
290 this, 257 this,
291 _changeDetector.newGroup(), 258 _changeDetector.newGroup(),
292 context == null ? this.context : context, 259 context == null ? this.context : context,
293 <String, WatchRecord<_Handler>>{}, 260 context == null ? this._cache: <String, WatchRecord<_Handler>>{},
294 _rootGroup == null ? this : _rootGroup); 261 _rootGroup == null ? this : _rootGroup);
295 _WatchGroupList._add(this, childGroup); 262 _WatchGroupList._add(this, childGroup);
296 var marker = childGroup._marker; 263 var marker = childGroup._marker;
297 264
298 marker._prevEvalWatch = prev; 265 marker._previousEvalWatch = prev;
299 marker._nextEvalWatch = next; 266 marker._nextEvalWatch = next;
300 prev._nextEvalWatch = marker; 267 if (prev != null) prev._nextEvalWatch = marker;
301 if (next != null) next._prevEvalWatch = marker; 268 if (next != null) next._previousEvalWatch = marker;
302 269
303 return childGroup; 270 return childGroup;
304 } 271 }
305 272
306 /** 273 /**
307 * Remove/destroy [WatchGroup] and all of its [Watches]. 274 * Remove/destroy [WatchGroup] and all of its [Watches].
308 */ 275 */
309 void remove() { 276 void remove() {
310 // TODO:(misko) This code is not right. 277 // TODO:(misko) This code is not right.
311 // 1) It fails to release [ChangeDetector] [WatchRecord]s. 278 // 1) It fails to release [ChangeDetector] [WatchRecord]s.
279 // 2) it needs to cleanup caches if the cache is being shared.
312 280
313 _WatchGroupList._remove(_parentWatchGroup, this); 281 _WatchGroupList._remove(_parentWatchGroup, this);
314 _nextWatchGroup = _prevWatchGroup = null;
315 _changeDetector.remove(); 282 _changeDetector.remove();
316 _rootGroup._removeCount++; 283 _rootGroup._removeCount++;
317 _parentWatchGroup = null; 284 _parentWatchGroup = null;
318 285
319 // Unlink the _watchRecord 286 // Unlink the _watchRecord
320 _EvalWatchRecord firstEvalWatch = _evalWatchHead; 287 _EvalWatchRecord firstEvalWatch = _evalWatchHead;
321 _EvalWatchRecord lastEvalWatch = _childWatchGroupTail._evalWatchTail; 288 _EvalWatchRecord lastEvalWatch =
322 _EvalWatchRecord previous = firstEvalWatch._prevEvalWatch; 289 (_watchGroupTail == null ? this : _watchGroupTail)._evalWatchTail;
290 _EvalWatchRecord previous = firstEvalWatch._previousEvalWatch;
323 _EvalWatchRecord next = lastEvalWatch._nextEvalWatch; 291 _EvalWatchRecord next = lastEvalWatch._nextEvalWatch;
324 if (previous != null) previous._nextEvalWatch = next; 292 if (previous != null) previous._nextEvalWatch = next;
325 if (next != null) next._prevEvalWatch = previous; 293 if (next != null) next._previousEvalWatch = previous;
326 _evalWatchHead._prevEvalWatch = null;
327 _evalWatchTail._nextEvalWatch = null;
328 _evalWatchHead = _evalWatchTail = null;
329 } 294 }
330 295
331 toString() { 296 toString() {
332 var lines = []; 297 var lines = [];
333 if (this == _rootGroup) { 298 if (this == _rootGroup) {
334 var allWatches = []; 299 var allWatches = [];
335 var watch = _evalWatchHead; 300 var watch = _evalWatchHead;
336 var prev = null; 301 var prev = null;
337 while (watch != null) { 302 while (watch != null) {
338 allWatches.add(watch.toString()); 303 allWatches.add(watch.toString());
339 assert(watch._prevEvalWatch == prev); 304 assert(watch._previousEvalWatch == prev);
340 prev = watch; 305 prev = watch;
341 watch = watch._nextEvalWatch; 306 watch = watch._nextEvalWatch;
342 } 307 }
343 lines.add('WATCHES: ${allWatches.join(', ')}'); 308 lines.add('WATCHES: ${allWatches.join(', ')}');
344 } 309 }
345 310
346 var watches = []; 311 var watches = [];
347 var watch = _evalWatchHead; 312 var watch = _evalWatchHead;
348 while (watch != _evalWatchTail) { 313 while (watch != _evalWatchTail) {
349 watches.add(watch.toString()); 314 watches.add(watch.toString());
350 watch = watch._nextEvalWatch; 315 watch = watch._nextEvalWatch;
351 } 316 }
352 watches.add(watch.toString()); 317 watches.add(watch.toString());
353 318
354 lines.add('WatchGroup[$id](watches: ${watches.join(', ')})'); 319 lines.add('WatchGroup[$id](watches: ${watches.join(', ')})');
355 var childGroup = _watchGroupHead; 320 var childGroup = _watchGroupHead;
356 while (childGroup != null) { 321 while (childGroup != null) {
357 lines.add(' ' + childGroup.toString().replace('\n', '\n ')); 322 lines.add(' ' + childGroup.toString().split('\n').join('\n '));
358 childGroup = childGroup._nextWatchGroup; 323 childGroup = childGroup._nextWatchGroup;
359 } 324 }
360 return lines.join('\n'); 325 return lines.join('\n');
361 } 326 }
362 } 327 }
363 328
364 /** 329 /**
365 * [RootWatchGroup] 330 * [RootWatchGroup]
366 */ 331 */
367 class RootWatchGroup extends WatchGroup { 332 class RootWatchGroup extends WatchGroup {
368 final FieldGetterFactory _fieldGetterFactory;
369 Watch _dirtyWatchHead, _dirtyWatchTail; 333 Watch _dirtyWatchHead, _dirtyWatchTail;
370 334
371 /** 335 /**
372 * Every time a [WatchGroup] is destroyed we increment the counter. During 336 * Every time a [WatchGroup] is destroyed we increment the counter. During
373 * [detectChanges] we reset the count. Before calling the reaction function, 337 * [detectChanges] we reset the count. Before calling the reaction function,
374 * we check [_removeCount] and if it is unchanged we can safely call the 338 * we check [_removeCount] and if it is unchanged we can safely call the
375 * reaction function. If it is changed we only call the reaction function 339 * reaction function. If it is changed we only call the reaction function
376 * if the [WatchGroup] is still attached. 340 * if the [WatchGroup] is still attached.
377 */ 341 */
378 int _removeCount = 0; 342 int _removeCount = 0;
379 343
380 344
381 RootWatchGroup(this._fieldGetterFactory, 345 RootWatchGroup(ChangeDetector changeDetector, Object context):
382 ChangeDetector changeDetector, 346 super._root(changeDetector, context);
383 Object context)
384 : super._root(changeDetector, context);
385 347
386 RootWatchGroup get _rootGroup => this; 348 RootWatchGroup get _rootGroup => this;
387 349
388 /** 350 /**
389 * Detect changes and process the [ReactionFn]s. 351 * Detect changes and process the [ReactionFn]s.
390 * 352 *
391 * Algorithm: 353 * Algorithm:
392 * 1) process the [ChangeDetector#collectChanges]. 354 * 1) process the [ChangeDetector#collectChanges].
393 * 2) process function/closure/method changes 355 * 2) process function/closure/method changes
394 * 3) call an [ReactionFn]s 356 * 3) call an [ReactionFn]s
395 * 357 *
396 * Each step is called in sequence. ([ReactionFn]s are not called until all 358 * Each step is called in sequence. ([ReactionFn]s are not called until all
397 * previous steps are completed). 359 * previous steps are completed).
398 */ 360 */
399 int detectChanges({ EvalExceptionHandler exceptionHandler, 361 int detectChanges({ EvalExceptionHandler exceptionHandler,
400 ChangeLog changeLog, 362 ChangeLog changeLog,
401 AvgStopwatch fieldStopwatch, 363 AvgStopwatch fieldStopwatch,
402 AvgStopwatch evalStopwatch, 364 AvgStopwatch evalStopwatch,
403 AvgStopwatch processStopwatch}) { 365 AvgStopwatch processStopwatch}) {
404 // Process the Records from the change detector 366 // Process the ChangeRecords from the change detector
405 Iterator<Record<_Handler>> changedRecordIterator = 367 ChangeRecord<_Handler> changeRecord =
406 (_changeDetector as ChangeDetector<_Handler>).collectChanges( 368 (_changeDetector as ChangeDetector<_Handler>).collectChanges(
407 exceptionHandler:exceptionHandler, 369 exceptionHandler:exceptionHandler,
408 stopwatch: fieldStopwatch); 370 stopwatch: fieldStopwatch);
409 if (processStopwatch != null) processStopwatch.start(); 371 if (processStopwatch != null) processStopwatch.start();
410 while (changedRecordIterator.moveNext()) { 372 while (changeRecord != null) {
411 var record = changedRecordIterator.current; 373 if (changeLog != null) changeLog(changeRecord.handler.expression,
412 if (changeLog != null) changeLog(record.handler.expression, 374 changeRecord.currentValue,
413 record.currentValue, 375 changeRecord.previousValue);
414 record.previousValue); 376 changeRecord.handler.onChange(changeRecord);
415 record.handler.onChange(record); 377 changeRecord = changeRecord.nextChange;
416 } 378 }
417 if (processStopwatch != null) processStopwatch.stop(); 379 if (processStopwatch != null) processStopwatch.stop();
418 380
419 if (evalStopwatch != null) evalStopwatch.start(); 381 if (evalStopwatch != null) evalStopwatch.start();
420 // Process our own function evaluations 382 // Process our own function evaluations
421 _EvalWatchRecord evalRecord = _evalWatchHead; 383 _EvalWatchRecord evalRecord = _evalWatchHead;
422 int evalCount = 0; 384 int evalCount = 0;
423 while (evalRecord != null) { 385 while (evalRecord != null) {
424 try { 386 try {
425 if (evalStopwatch != null) evalCount++; 387 if (evalStopwatch != null) evalCount++;
426 if (evalRecord.check() && changeLog != null) { 388 var change = evalRecord.check();
389 if (change != null && changeLog != null) {
427 changeLog(evalRecord.handler.expression, 390 changeLog(evalRecord.handler.expression,
428 evalRecord.currentValue, 391 evalRecord.currentValue,
429 evalRecord.previousValue); 392 evalRecord.previousValue);
430 } 393 }
431 } catch (e, s) { 394 } catch (e, s) {
432 if (exceptionHandler == null) rethrow; else exceptionHandler(e, s); 395 if (exceptionHandler == null) rethrow; else exceptionHandler(e, s);
433 } 396 }
434 evalRecord = evalRecord._nextEvalWatch; 397 evalRecord = evalRecord._nextEvalWatch;
435 } 398 }
436 if (evalStopwatch != null) evalStopwatch..stop()..increment(evalCount); 399 if (evalStopwatch != null) evalStopwatch..stop()..increment(evalCount);
437 400
438 // Because the handler can forward changes between each other synchronously 401 // Because the handler can forward changes between each other synchronously
439 // We need to call reaction functions asynchronously. This processes the 402 // We need to call reaction functions asynchronously. This processes the
440 // asynchronous reaction function queue. 403 // asynchronous reaction function queue.
441 int count = 0; 404 int count = 0;
442 if (processStopwatch != null) processStopwatch.start(); 405 if (processStopwatch != null) processStopwatch.stop();
443 Watch dirtyWatch = _dirtyWatchHead; 406 Watch dirtyWatch = _dirtyWatchHead;
444 _dirtyWatchHead = null;
445 RootWatchGroup root = _rootGroup; 407 RootWatchGroup root = _rootGroup;
446 try { 408 root._removeCount = 0;
447 while (dirtyWatch != null) { 409 while(dirtyWatch != null) {
448 count++; 410 count++;
449 try { 411 try {
450 if (root._removeCount == 0 || dirtyWatch._watchGroup.isAttached) { 412 if (root._removeCount == 0 || dirtyWatch._watchGroup.isAttached) {
451 dirtyWatch.invoke(); 413 dirtyWatch.invoke();
452 }
453 } catch (e, s) {
454 if (exceptionHandler == null) rethrow; else exceptionHandler(e, s);
455 } 414 }
456 var nextDirtyWatch = dirtyWatch._nextDirtyWatch; 415 } catch (e, s) {
457 dirtyWatch._nextDirtyWatch = null; 416 if (exceptionHandler == null) rethrow; else exceptionHandler(e, s);
458 dirtyWatch = nextDirtyWatch;
459 } 417 }
460 } finally { 418 dirtyWatch = dirtyWatch._nextDirtyWatch;
461 _dirtyWatchTail = null;
462 root._removeCount = 0;
463 } 419 }
420 _dirtyWatchHead = _dirtyWatchTail = null;
464 if (processStopwatch != null) processStopwatch..stop()..increment(count); 421 if (processStopwatch != null) processStopwatch..stop()..increment(count);
465 return count; 422 return count;
466 } 423 }
467 424
468 bool get isInsideInvokeDirty =>
469 _dirtyWatchHead == null && _dirtyWatchTail != null;
470
471 /** 425 /**
472 * Add Watch into the asynchronous queue for later processing. 426 * Add Watch into the asynchronous queue for later processing.
473 */ 427 */
474 Watch _addDirtyWatch(Watch watch) { 428 Watch _addDirtyWatch(Watch watch) {
475 if (!watch._dirty) { 429 if (!watch._dirty) {
476 watch._dirty = true; 430 watch._dirty = true;
477 if (_dirtyWatchTail == null) { 431 if (_dirtyWatchTail == null) {
478 _dirtyWatchHead = _dirtyWatchTail = watch; 432 _dirtyWatchHead = _dirtyWatchTail = watch;
479 } else { 433 } else {
480 _dirtyWatchTail._nextDirtyWatch = watch; 434 _dirtyWatchTail._nextDirtyWatch = watch;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 * - delegateHandler -+ - delegateHandler -+ - delegateHandler = nul l 483 * - delegateHandler -+ - delegateHandler -+ - delegateHandler = nul l
530 * - expression: 'a' - expression: 'a.b' - expression: 'a.b.c' 484 * - expression: 'a' - expression: 'a.b' - expression: 'a.b.c'
531 * - watchObject: context - watchObject: context.a - watchObject: context. a.b 485 * - watchObject: context - watchObject: context.a - watchObject: context. a.b
532 * - watchRecord: 'a' - watchRecord 'b' - watchRecord 'c' 486 * - watchRecord: 'a' - watchRecord 'b' - watchRecord 'c'
533 * - reactionFn: null - reactionFn: rfn1 - reactionFn: rfn2 487 * - reactionFn: null - reactionFn: rfn1 - reactionFn: rfn2
534 * 488 *
535 * Notice how the [_Handler]s coalesce their watching. Also notice that any 489 * Notice how the [_Handler]s coalesce their watching. Also notice that any
536 * changes detected at one handler are propagated to the next handler. 490 * changes detected at one handler are propagated to the next handler.
537 */ 491 */
538 abstract class _Handler implements _LinkedList, _LinkedListItem, _WatchList { 492 abstract class _Handler implements _LinkedList, _LinkedListItem, _WatchList {
539 // Used for forwarding changes to delegates
540 _Handler _head, _tail; 493 _Handler _head, _tail;
541 _Handler _next, _previous; 494 _Handler _next, _previous;
542 Watch _watchHead, _watchTail; 495 Watch _watchHead, _watchTail;
543 496
544 final String expression; 497 final String expression;
545 final WatchGroup watchGrp; 498 final WatchGroup watchGrp;
546 499
547 WatchRecord<_Handler> watchRecord; 500 WatchRecord<_Handler> watchRecord;
548 _Handler forwardingHandler; 501 _Handler forwardingHandler;
549 502
550 _Handler(this.watchGrp, this.expression) { 503 _Handler(this.watchGrp, this.expression) {
551 assert(watchGrp != null); 504 assert(watchGrp != null);
552 assert(expression != null); 505 assert(expression != null);
553 } 506 }
554 507
555 Watch addReactionFn(ReactionFn reactionFn) { 508 Watch addReactionFn(ReactionFn reactionFn) {
556 assert(_next != this); // verify we are not detached 509 assert(_next != this); // verify we are not detached
557 return watchGrp._rootGroup._addDirtyWatch(_WatchList._add(this, 510 return watchGrp._rootGroup._addDirtyWatch(_WatchList._add(this,
558 new Watch(watchGrp, watchRecord, reactionFn))); 511 new Watch(watchGrp, watchRecord, reactionFn)));
559 } 512 }
560 513
561 void addForwardHandler(_Handler forwardToHandler) { 514 void addForwardHandler(_Handler forwardToHandler) {
562 assert(forwardToHandler.forwardingHandler == null); 515 assert(forwardToHandler.forwardingHandler == null);
563 _LinkedList._add(this, forwardToHandler); 516 _LinkedList._add(this, forwardToHandler);
564 forwardToHandler.forwardingHandler = this; 517 forwardToHandler.forwardingHandler = this;
565 } 518 }
566 519
567 /// Return true if release has happened 520 void release() {
568 bool release() {
569 if (_WatchList._isEmpty(this) && _LinkedList._isEmpty(this)) { 521 if (_WatchList._isEmpty(this) && _LinkedList._isEmpty(this)) {
570 _releaseWatch(); 522 _releaseWatch();
571 // Remove ourselves from cache, or else new registrations will go to us, 523 // Remove ourselves from cache, or else new registrations will go to us,
572 // but we are dead 524 // but we are dead
573 watchGrp._cache.remove(expression); 525 watchGrp._cache.remove(expression);
574 526
575 if (forwardingHandler != null) { 527 if (forwardingHandler != null) {
576 // TODO(misko): why do we need this check? 528 // TODO(misko): why do we need this check?
577 _LinkedList._remove(forwardingHandler, this); 529 _LinkedList._remove(forwardingHandler, this);
578 forwardingHandler.release(); 530 forwardingHandler.release();
579 } 531 }
580 532
581 // We can remove ourselves 533 // We can remove ourselves
582 assert((_next = _previous = this) == this); // mark ourselves as detached 534 assert((_next = _previous = this) == this); // mark ourselves as detached
583 return true;
584 } else {
585 return false;
586 } 535 }
587 } 536 }
588 537
589 void _releaseWatch() { 538 void _releaseWatch() {
590 watchRecord.remove(); 539 watchRecord.remove();
591 watchGrp._fieldCost--; 540 watchGrp._fieldCost--;
592 } 541 }
593 acceptValue(object) => null; 542 acceptValue(object) => null;
594 543
595 void onChange(Record<_Handler> record) { 544 void onChange(ChangeRecord<_Handler> record) {
596 assert(_next != this); // verify we are not detached 545 assert(_next != this); // verify we are not detached
597 // If we have reaction functions than queue them up for asynchronous 546 // If we have reaction functions than queue them up for asynchronous
598 // processing. 547 // processing.
599 Watch watch = _watchHead; 548 Watch watch = _watchHead;
600 while (watch != null) { 549 while(watch != null) {
601 watchGrp._rootGroup._addDirtyWatch(watch); 550 watchGrp._rootGroup._addDirtyWatch(watch);
602 watch = watch._nextWatch; 551 watch = watch._nextWatch;
603 } 552 }
604 // If we have a delegateHandler then forward the new value to it. 553 // If we have a delegateHandler then forward the new value to it.
605 _Handler delegateHandler = _head; 554 _Handler delegateHandler = _head;
606 while (delegateHandler != null) { 555 while (delegateHandler != null) {
607 delegateHandler.acceptValue(record.currentValue); 556 delegateHandler.acceptValue(record.currentValue);
608 delegateHandler = delegateHandler._next; 557 delegateHandler = delegateHandler._next;
609 } 558 }
610 } 559 }
611 } 560 }
612 561
613 class _ConstantHandler extends _Handler { 562 class _ConstantHandler extends _Handler {
614 _ConstantHandler(WatchGroup watchGroup, String expression, constantValue) 563 _ConstantHandler(WatchGroup watchGroup, String expression, dynamic constantVal ue)
615 : super(watchGroup, expression) 564 : super(watchGroup, expression)
616 { 565 {
617 watchRecord = new _EvalWatchRecord.constant(this, constantValue); 566 watchRecord = new _EvalWatchRecord.constant(this, constantValue);
618 } 567 }
619 release() => null; 568 release() => null;
620 } 569 }
621 570
622 class _FieldHandler extends _Handler { 571 class _FieldHandler extends _Handler {
623 _FieldHandler(watchGrp, expression): super(watchGrp, expression); 572 _FieldHandler(watchGrp, expression): super(watchGrp, expression);
624 573
625 /** 574 /**
626 * This function forwards the watched object to the next [_Handler] 575 * This function forwards the watched object to the next [_Handler]
627 * synchronously. 576 * synchronously.
628 */ 577 */
629 void acceptValue(object) { 578 void acceptValue(object) {
630 watchRecord.object = object; 579 watchRecord.object = object;
631 if (watchRecord.check()) onChange(watchRecord); 580 var changeRecord = watchRecord.check();
581 if (changeRecord != null) onChange(changeRecord);
632 } 582 }
633 } 583 }
634 584
635 class _CollectionHandler extends _Handler { 585 class _CollectionHandler extends _Handler {
636 _CollectionHandler(WatchGroup watchGrp, String expression) 586 _CollectionHandler(WatchGroup watchGrp, String expression)
637 : super(watchGrp, expression); 587 : super(watchGrp, expression);
638 /** 588 /**
639 * This function forwards the watched object to the next [_Handler] synchronou sly. 589 * This function forwards the watched object to the next [_Handler] synchronou sly.
640 */ 590 */
641 void acceptValue(object) { 591 void acceptValue(object) {
642 watchRecord.object = object; 592 watchRecord.object = object;
643 if (watchRecord.check()) onChange(watchRecord); 593 var changeRecord = watchRecord.check();
594 if (changeRecord != null) onChange(changeRecord);
644 } 595 }
645 596
646 void _releaseWatch() { 597 void _releaseWatch() {
647 watchRecord.remove(); 598 watchRecord.remove();
648 watchGrp._collectionCost--; 599 watchGrp._collectionCost--;
649 } 600 }
650 } 601 }
651 602
652 abstract class _ArgHandler extends _Handler { 603 class _ArgHandler extends _Handler {
653 _ArgHandler _previousArgHandler, _nextArgHandler; 604 _ArgHandler _previousArgHandler, _nextArgHandler;
654 605
655 // TODO(misko): Why do we override parent? 606 // TODO(misko): Why do we override parent?
656 final _EvalWatchRecord watchRecord; 607 final _EvalWatchRecord watchRecord;
657 _ArgHandler(WatchGroup watchGrp, String expression, this.watchRecord) 608 final int index;
658 : super(watchGrp, expression);
659 609
660 _releaseWatch() => null; 610 _releaseWatch() => null;
661 }
662 611
663 class _PositionalArgHandler extends _ArgHandler { 612 _ArgHandler(WatchGroup watchGrp, this.watchRecord, int index)
664 final int index; 613 : index = index,
665 _PositionalArgHandler(WatchGroup watchGrp, _EvalWatchRecord record, int index) 614 super(watchGrp, 'arg[$index]');
666 : this.index = index,
667 super(watchGrp, 'arg[$index]', record);
668 615
669 void acceptValue(object) { 616 void acceptValue(object) {
670 watchRecord.dirtyArgs = true; 617 watchRecord.dirtyArgs = true;
671 watchRecord.args[index] = object; 618 watchRecord.args[index] = object;
672 } 619 }
673 } 620 }
674 621
675 class _NamedArgHandler extends _ArgHandler {
676 final Symbol name;
677
678 _NamedArgHandler(WatchGroup watchGrp, _EvalWatchRecord record, Symbol name)
679 : this.name = name,
680 super(watchGrp, 'namedArg[$name]', record);
681
682 void acceptValue(object) {
683 watchRecord.dirtyArgs = true;
684 watchRecord.namedArgs[name] = object;
685 }
686 }
687
688 class _InvokeHandler extends _Handler implements _ArgHandlerList { 622 class _InvokeHandler extends _Handler implements _ArgHandlerList {
689 _ArgHandler _argHandlerHead, _argHandlerTail; 623 _ArgHandler _argHandlerHead, _argHandlerTail;
690 624
691 _InvokeHandler(WatchGroup watchGrp, String expression) 625 _InvokeHandler(WatchGroup watchGrp, String expression)
692 : super(watchGrp, expression); 626 : super(watchGrp, expression);
693 627
694 void acceptValue(object) { 628 void acceptValue(object) {
695 watchRecord.object = object; 629 watchRecord.object = object;
696 } 630 }
697 631
632 void onChange(ChangeRecord<_Handler> record) {
633 super.onChange(record);
634 }
635
698 void _releaseWatch() { 636 void _releaseWatch() {
699 (watchRecord as _EvalWatchRecord).remove(); 637 (watchRecord as _EvalWatchRecord).remove();
700 } 638 }
701 639
702 bool release() { 640 void release() {
703 if (super.release()) { 641 super.release();
704 _ArgHandler current = _argHandlerHead; 642 _ArgHandler current = _argHandlerHead;
705 while (current != null) { 643 while(current != null) {
706 current.release(); 644 current.release();
707 current = current._nextArgHandler; 645 current = current._nextArgHandler;
708 }
709 return true;
710 } else {
711 return false;
712 } 646 }
713 } 647 }
714 } 648 }
715 649
716 650
717 class _EvalWatchRecord implements WatchRecord<_Handler> { 651 class _EvalWatchRecord implements WatchRecord<_Handler>, ChangeRecord<_Handler> {
718 static const int _MODE_INVALID_ = -2; 652 static const int _MODE_DELETED_ = -1;
719 static const int _MODE_DELETED_ = -1; 653 static const int _MODE_MARKER_ = 0;
720 static const int _MODE_MARKER_ = 0; 654 static const int _MODE_FUNCTION_ = 1;
721 static const int _MODE_PURE_FUNCTION_ = 1; 655 static const int _MODE_FUNCTION_APPLY_ = 2;
722 static const int _MODE_FUNCTION_ = 2; 656 static const int _MODE_NULL_ = 3;
723 static const int _MODE_PURE_FUNCTION_APPLY_ = 3; 657 static const int _MODE_FIELD_CLOSURE_ = 4;
724 static const int _MODE_NULL_ = 4; 658 static const int _MODE_MAP_CLOSURE_ = 5;
725 static const int _MODE_FIELD_CLOSURE_ = 5; 659 static const int _MODE_METHOD_ = 6;
726 static const int _MODE_MAP_CLOSURE_ = 6;
727 static const int _MODE_METHOD_ = 7;
728 static const int _MODE_METHOD_INVOKE_ = 8;
729 WatchGroup watchGrp; 660 WatchGroup watchGrp;
730 final _Handler handler; 661 final _Handler handler;
731 final List args; 662 final List args;
732 final Map<Symbol, dynamic> namedArgs = new Map<Symbol, dynamic>(); 663 final Symbol symbol;
733 final String name; 664 final String name;
734 int mode; 665 int mode;
735 /* dartbug.com/16401 Function*/ var fn; 666 /* dartbug.com/16401 Function*/ var fn;
736 FieldGetterFactory _fieldGetterFactory; 667 InstanceMirror _instanceMirror;
737 bool dirtyArgs = true; 668 bool dirtyArgs = true;
738 669
739 dynamic currentValue, previousValue, _object; 670 dynamic currentValue, previousValue, _object;
740 _EvalWatchRecord _prevEvalWatch, _nextEvalWatch; 671 _EvalWatchRecord _previousEvalWatch, _nextEvalWatch;
741 672
742 _EvalWatchRecord(this._fieldGetterFactory, this.watchGrp, this.handler, 673 _EvalWatchRecord(this.watchGrp, this.handler, this.fn, name, int arity)
743 this.fn, this.name, int arity, bool pure) 674 : args = new List(arity),
744 : args = new List(arity) 675 name = name,
745 { 676 symbol = name == null ? null : new Symbol(name) {
746 if (fn is FunctionApply) { 677 if (fn is FunctionApply) {
747 mode = pure ? _MODE_PURE_FUNCTION_APPLY_: _MODE_INVALID_; 678 mode = _MODE_FUNCTION_APPLY_;
748 } else if (fn is Function) { 679 } else if (fn is Function) {
749 mode = pure ? _MODE_PURE_FUNCTION_ : _MODE_FUNCTION_; 680 mode = _MODE_FUNCTION_;
750 } else { 681 } else {
751 mode = _MODE_NULL_; 682 mode = _MODE_NULL_;
752 } 683 }
753 } 684 }
754 685
755 _EvalWatchRecord.marker() 686 _EvalWatchRecord.marker()
756 : mode = _MODE_MARKER_, 687 : mode = _MODE_MARKER_,
757 _fieldGetterFactory = null,
758 watchGrp = null, 688 watchGrp = null,
759 handler = null, 689 handler = null,
760 args = null, 690 args = null,
761 fn = null, 691 fn = null,
692 symbol = null,
762 name = null; 693 name = null;
763 694
764 _EvalWatchRecord.constant(_Handler handler, dynamic constantValue) 695 _EvalWatchRecord.constant(_Handler handler, dynamic constantValue)
765 : mode = _MODE_MARKER_, 696 : mode = _MODE_MARKER_,
766 _fieldGetterFactory = null,
767 handler = handler, 697 handler = handler,
768 currentValue = constantValue, 698 currentValue = constantValue,
769 watchGrp = null, 699 watchGrp = null,
770 args = null, 700 args = null,
771 fn = null, 701 fn = null,
702 symbol = null,
772 name = null; 703 name = null;
773 704
774 get field => '()'; 705 get field => '()';
775 706
776 get object => _object; 707 get object => _object;
777 708
778 set object(value) { 709 set object(value) {
779 assert(mode != _MODE_DELETED_); 710 assert(mode != _MODE_DELETED_);
780 assert(mode != _MODE_MARKER_); 711 assert(mode != _MODE_MARKER_);
781 assert(mode != _MODE_FUNCTION_); 712 assert(mode != _MODE_FUNCTION_);
782 assert(mode != _MODE_PURE_FUNCTION_); 713 assert(mode != _MODE_FUNCTION_APPLY_);
783 assert(mode != _MODE_PURE_FUNCTION_APPLY_); 714 assert(symbol != null);
784 _object = value; 715 _object = value;
785 716
786 if (value == null) { 717 if (value == null) {
787 mode = _MODE_NULL_; 718 mode = _MODE_NULL_;
788 } else { 719 } else {
789 if (value is Map) { 720 if (value is Map) {
790 mode = _MODE_MAP_CLOSURE_; 721 mode = _MODE_MAP_CLOSURE_;
791 } else { 722 } else {
792 if (_fieldGetterFactory.isMethod(value, name)) { 723 _instanceMirror = reflect(value);
793 mode = _fieldGetterFactory.isMethodInvoke ? _MODE_METHOD_INVOKE_ : _MO DE_METHOD_; 724 mode = _hasMethod(_instanceMirror.type, symbol)
794 fn = _fieldGetterFactory.method(value, name); 725 ? _MODE_METHOD_
795 } else { 726 : _MODE_FIELD_CLOSURE_;
796 mode = _MODE_FIELD_CLOSURE_;
797 fn = _fieldGetterFactory.getter(value, name);
798 }
799 } 727 }
800 } 728 }
801 } 729 }
802 730
803 bool check() { 731 ChangeRecord<_Handler> check() {
804 var value; 732 var value;
805 switch (mode) { 733 switch (mode) {
806 case _MODE_MARKER_: 734 case _MODE_MARKER_:
807 case _MODE_NULL_: 735 case _MODE_NULL_:
808 return false; 736 return null;
809 case _MODE_PURE_FUNCTION_: 737 case _MODE_FUNCTION_:
810 if (!dirtyArgs) return false; 738 if (!dirtyArgs) return null;
811 value = Function.apply(fn, args, namedArgs); 739 value = Function.apply(fn, args);
812 dirtyArgs = false; 740 dirtyArgs = false;
813 break; 741 break;
814 case _MODE_FUNCTION_: 742 case _MODE_FUNCTION_APPLY_:
815 value = Function.apply(fn, args, namedArgs); 743 if (!dirtyArgs) return null;
816 dirtyArgs = false;
817 break;
818 case _MODE_PURE_FUNCTION_APPLY_:
819 if (!dirtyArgs) return false;
820 value = (fn as FunctionApply).apply(args); 744 value = (fn as FunctionApply).apply(args);
821 dirtyArgs = false; 745 dirtyArgs = false;
822 break; 746 break;
823 case _MODE_FIELD_CLOSURE_: 747 case _MODE_FIELD_CLOSURE_:
824 var closure = fn(_object); 748 var closure = _instanceMirror.getField(symbol).reflectee;
825 value = closure == null ? null : Function.apply(closure, args, namedArgs ); 749 value = closure == null ? null : Function.apply(closure, args);
826 break; 750 break;
827 case _MODE_MAP_CLOSURE_: 751 case _MODE_MAP_CLOSURE_:
828 var closure = object[name]; 752 var closure = object[name];
829 value = closure == null ? null : Function.apply(closure, args, namedArgs ); 753 value = closure == null ? null : Function.apply(closure, args);
830 break; 754 break;
831 case _MODE_METHOD_: 755 case _MODE_METHOD_:
832 value = Function.apply(fn, args, namedArgs); 756 value = _instanceMirror.invoke(symbol, args).reflectee;
833 break;
834 case _MODE_METHOD_INVOKE_:
835 value = fn(args, namedArgs);
836 break; 757 break;
837 default: 758 default:
838 assert(false); 759 assert(false);
839 } 760 }
840 761
841 var current = currentValue; 762 var current = currentValue;
842 if (!identical(current, value)) { 763 if (!identical(current, value)) {
843 if (value is String && current is String && value == current) { 764 if (value is String && current is String && value == current) {
844 // it is really the same, recover and save so next time identity is same 765 // it is really the same, recover and save so next time identity is same
845 current = value; 766 current = value;
846 } else { 767 } else {
847 previousValue = current; 768 previousValue = current;
848 currentValue = value; 769 currentValue = value;
849 handler.onChange(this); 770 handler.onChange(this);
850 return true; 771 return this;
851 } 772 }
852 } 773 }
853 return false; 774 return null;
854 } 775 }
855 776
856 get nextChange => null; 777 get nextChange => null;
857 778
858 void remove() { 779 void remove() {
859 assert(mode != _MODE_DELETED_); 780 assert(mode != _MODE_DELETED_);
860 assert((mode = _MODE_DELETED_) == _MODE_DELETED_); // Mark as deleted. 781 assert((mode = _MODE_DELETED_) == _MODE_DELETED_); // Mark as deleted.
861 watchGrp._evalCost--; 782 watchGrp._evalCost--;
862 _EvalWatchList._remove(watchGrp, this); 783 _EvalWatchList._remove(watchGrp, this);
863 } 784 }
864 785
865 String toString() { 786 String toString() {
866 if (mode == _MODE_MARKER_) return 'MARKER[$currentValue]'; 787 if (mode == _MODE_MARKER_) return 'MARKER[$currentValue]';
867 return '${watchGrp.id}:${handler.expression}'; 788 return '${watchGrp.id}:${handler.expression}';
868 } 789 }
790
791 static final Function _hasMethod = (() {
792 var objectClassMirror = reflectClass(Object);
793 Set<Symbol> objectClassInstanceMethods =
794 new Set<Symbol>.from([#toString, #noSuchMethod]);
795 try {
796 // Use ClassMirror.instanceMembers if available. It contains local
797 // as well as inherited members.
798 objectClassMirror.instanceMembers;
799 // For SDK 1.2 we have to use a somewhat complicated helper for this
800 // to work around bugs in the dart2js implementation.
801 return (type, symbol) {
802 // Always allow instance methods found in the Object class. This makes
803 // it easier to work around a few bugs in the dart2js implementation.
804 if (objectClassInstanceMethods.contains(symbol)) return true;
805 // Work around http://dartbug.com/16309 which causes access to the
806 // instance members of certain builtin types to throw exceptions
807 // while traversing the superclass chain.
808 var mirror;
809 try {
810 mirror = type.instanceMembers[symbol];
811 } on UnsupportedError catch (e) {
812 mirror = type.declarations[symbol];
813 }
814 // Work around http://dartbug.com/15760 which causes noSuchMethod
815 // forwarding stubs to be treated as members of all classes. We have
816 // already checked for the real instance methods in Object, so if the
817 // owner of this method is Object we simply filter it out.
818 if (mirror is !MethodMirror) return false;
819 return mirror.owner != objectClassMirror;
820 };
821 } on NoSuchMethodError catch (e) {
822 // For SDK 1.0 we fall back to just using the local members.
823 return (type, symbol) => type.members[symbol] is MethodMirror;
824 } on UnimplementedError catch (e) {
825 // For SDK 1.1 we fall back to just using the local declarations.
826 return (type, symbol) => type.declarations[symbol] is MethodMirror;
827 }
828 return null;
829 })();
830
869 } 831 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698