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

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

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

Powered by Google App Engine
This is Rietveld 408576698