11import { ProtoRecord , Record } from './record' ;
2- import { FIELD } from 'facade/lang' ;
3- import { ListWrapper } from 'facade/collection ' ;
2+ import { FIELD , IMPLEMENTS , isBlank , isPresent } from 'facade/lang' ;
3+ import { AST , FieldRead , ImplicitReceiver , AstVisitor } from './parser/ast ' ;
44
55export class ProtoWatchGroup {
6- @FIELD ( 'final headRecord:ProtoRecord' )
7- @FIELD ( 'final tailRecord:ProtoRecord' )
6+ @FIELD ( 'headRecord:ProtoRecord' )
7+ @FIELD ( 'tailRecord:ProtoRecord' )
88 constructor ( ) {
99 this . headRecord = null ;
1010 this . tailRecord = null ;
1111 }
1212
1313 /**
14- * Parses [expression ] into [ProtoRecord]s and adds them to [ProtoWatchGroup].
14+ * Parses [ast ] into [ProtoRecord]s and adds them to [ProtoWatchGroup].
1515 *
16- * @param expression The expression to watch
16+ * @param ast The expression to watch
1717 * @param memento an opaque object which will be passed to WatchGroupDispatcher on
1818 * detecting a change.
1919 * @param shallow Should collections be shallow watched
2020 */
21- watch ( expression : string ,
21+ watch ( ast : AST ,
2222 memento ,
2323 shallow = false )
2424 {
25- var parts = expression . split ( '.' ) ;
26- var protoRecords = ListWrapper . createFixedSize ( parts . length ) ;
25+ var creator = new ProtoRecordCreator ( this ) ;
26+ creator . createRecordsFromAST ( ast , memento ) ;
27+ this . _addRecords ( creator . headRecord , creator . tailRecord ) ;
28+ }
2729
28- for ( var i = parts . length - 1 ; i >= 0 ; i -- ) {
29- protoRecords [ i ] = new ProtoRecord ( this , parts [ i ] , memento ) ;
30- memento = null ;
31- }
32-
33- for ( var i = 0 ; i < parts . length ; i ++ ) {
34- var protoRecord = protoRecords [ i ] ;
35- if ( this . headRecord === null ) {
36- this . headRecord = this . tailRecord = protoRecord ;
37- } else {
38- this . tailRecord . next = protoRecord ;
39- protoRecord . prev = this . tailRecord ;
40- this . tailRecord = protoRecord ;
41- }
30+ // try to encapsulate this behavior in some class (e.g., LinkedList)
31+ // so we can say: group.appendList(creator.list);
32+ _addRecords ( head :ProtoRecord , tail :ProtoRecord ) {
33+ if ( isBlank ( this . headRecord ) ) {
34+ this . headRecord = head ;
35+ } else {
36+ this . tailRecord . next = head ;
37+ head . prev = this . tailRecord ;
4238 }
39+ this . tailRecord = tail ;
4340 }
4441
4542 instantiate ( dispatcher :WatchGroupDispatcher ) :WatchGroup {
@@ -109,3 +106,41 @@ export class WatchGroupDispatcher {
109106 // The record holds the previous value at the time of the call
110107 onRecordChange ( record :Record , context ) { }
111108}
109+
110+ @IMPLEMENTS ( AstVisitor )
111+ class ProtoRecordCreator {
112+ @FIELD ( 'final protoWatchGroup:ProtoWatchGroup' )
113+ @FIELD ( 'headRecord:ProtoRecord' )
114+ @FIELD ( 'tailRecord:ProtoRecord' )
115+ constructor ( protoWatchGroup ) {
116+ this . protoWatchGroup = protoWatchGroup ;
117+ this . headRecord = null ;
118+ this . tailRecord = null ;
119+ }
120+
121+ visitImplicitReceiver ( ast :ImplicitReceiver ) {
122+ //do nothing
123+ }
124+
125+ visitFieldRead ( ast :FieldRead ) {
126+ ast . receiver . visit ( this ) ;
127+ this . add ( new ProtoRecord ( this . protoWatchGroup , ast . name , null ) ) ;
128+ }
129+
130+ createRecordsFromAST ( ast :AST , memento ) {
131+ ast . visit ( this ) ;
132+ if ( isPresent ( this . tailRecord ) ) {
133+ this . tailRecord . dispatchMemento = memento ;
134+ }
135+ }
136+
137+ add ( protoRecord :ProtoRecord ) {
138+ if ( this . headRecord === null ) {
139+ this . headRecord = this . tailRecord = protoRecord ;
140+ } else {
141+ this . tailRecord . next = protoRecord ;
142+ protoRecord . prev = this . tailRecord ;
143+ this . tailRecord = protoRecord ;
144+ }
145+ }
146+ }
0 commit comments