11'use strict' ;
22
33var OPERATORS = {
4- 'null' :function ( self ) { return null ; } ,
5- 'true' :function ( self ) { return true ; } ,
6- 'false' :function ( self ) { return false ; } ,
4+ 'null' :function ( ) { return null ; } ,
5+ 'true' :function ( ) { return true ; } ,
6+ 'false' :function ( ) { return false ; } ,
77 undefined :noop ,
8- '+' :function ( self , a , b ) { a = a ( self ) ; b = b ( self ) ; return ( isDefined ( a ) ?a :0 ) + ( isDefined ( b ) ?b :0 ) ; } ,
9- '-' :function ( self , a , b ) { a = a ( self ) ; b = b ( self ) ; return ( isDefined ( a ) ?a :0 ) - ( isDefined ( b ) ?b :0 ) ; } ,
10- '*' :function ( self , a , b ) { return a ( self ) * b ( self ) ; } ,
11- '/' :function ( self , a , b ) { return a ( self ) / b ( self ) ; } ,
12- '%' :function ( self , a , b ) { return a ( self ) % b ( self ) ; } ,
13- '^' :function ( self , a , b ) { return a ( self ) ^ b ( self ) ; } ,
8+ '+' :function ( self , locals , a , b ) { a = a ( self , locals ) ; b = b ( self , locals ) ; return ( isDefined ( a ) ?a :0 ) + ( isDefined ( b ) ?b :0 ) ; } ,
9+ '-' :function ( self , locals , a , b ) { a = a ( self , locals ) ; b = b ( self , locals ) ; return ( isDefined ( a ) ?a :0 ) - ( isDefined ( b ) ?b :0 ) ; } ,
10+ '*' :function ( self , locals , a , b ) { return a ( self , locals ) * b ( self , locals ) ; } ,
11+ '/' :function ( self , locals , a , b ) { return a ( self , locals ) / b ( self , locals ) ; } ,
12+ '%' :function ( self , locals , a , b ) { return a ( self , locals ) % b ( self , locals ) ; } ,
13+ '^' :function ( self , locals , a , b ) { return a ( self , locals ) ^ b ( self , locals ) ; } ,
1414 '=' :noop ,
15- '==' :function ( self , a , b ) { return a ( self ) == b ( self ) ; } ,
16- '!=' :function ( self , a , b ) { return a ( self ) != b ( self ) ; } ,
17- '<' :function ( self , a , b ) { return a ( self ) < b ( self ) ; } ,
18- '>' :function ( self , a , b ) { return a ( self ) > b ( self ) ; } ,
19- '<=' :function ( self , a , b ) { return a ( self ) <= b ( self ) ; } ,
20- '>=' :function ( self , a , b ) { return a ( self ) >= b ( self ) ; } ,
21- '&&' :function ( self , a , b ) { return a ( self ) && b ( self ) ; } ,
22- '||' :function ( self , a , b ) { return a ( self ) || b ( self ) ; } ,
23- '&' :function ( self , a , b ) { return a ( self ) & b ( self ) ; } ,
24- // '|':function(self, a,b){return a|b;},
25- '|' :function ( self , a , b ) { return b ( self ) ( self , a ( self ) ) ; } ,
26- '!' :function ( self , a ) { return ! a ( self ) ; }
15+ '==' :function ( self , locals , a , b ) { return a ( self , locals ) == b ( self , locals ) ; } ,
16+ '!=' :function ( self , locals , a , b ) { return a ( self , locals ) != b ( self , locals ) ; } ,
17+ '<' :function ( self , locals , a , b ) { return a ( self , locals ) < b ( self , locals ) ; } ,
18+ '>' :function ( self , locals , a , b ) { return a ( self , locals ) > b ( self , locals ) ; } ,
19+ '<=' :function ( self , locals , a , b ) { return a ( self , locals ) <= b ( self , locals ) ; } ,
20+ '>=' :function ( self , locals , a , b ) { return a ( self , locals ) >= b ( self , locals ) ; } ,
21+ '&&' :function ( self , locals , a , b ) { return a ( self , locals ) && b ( self , locals ) ; } ,
22+ '||' :function ( self , locals , a , b ) { return a ( self , locals ) || b ( self , locals ) ; } ,
23+ '&' :function ( self , locals , a , b ) { return a ( self , locals ) & b ( self , locals ) ; } ,
24+ // '|':function(self, locals, a,b){return a|b;},
25+ '|' :function ( self , locals , a , b ) { return b ( self , locals ) ( self , locals , a ( self , locals ) ) ; } ,
26+ '!' :function ( self , locals , a ) { return ! a ( self , locals ) ; }
2727} ;
2828var ESCAPE = { "n" :"\n" , "f" :"\f" , "r" :"\r" , "t" :"\t" , "v" :"\v" , "'" :"'" , '"' :'"' } ;
2929
@@ -146,7 +146,7 @@ function lex(text){
146146 function readIdent ( ) {
147147 var ident = "" ,
148148 start = index ,
149- fn , lastDot , peekIndex , methodName ;
149+ fn , lastDot , peekIndex , methodName , getter ;
150150
151151 while ( index < text . length ) {
152152 var ch = text . charAt ( index ) ;
@@ -179,15 +179,21 @@ function lex(text){
179179 }
180180
181181 fn = OPERATORS [ ident ] ;
182+ getter = getterFn ( ident ) ;
182183 tokens . push ( {
183184 index :start ,
184185 text :ident ,
185186 json : fn ,
186- fn :fn || extend ( getterFn ( ident ) , {
187- assign :function ( self , value ) {
188- return setter ( self , ident , value ) ;
189- }
190- } )
187+ fn :fn || extend (
188+ function ( self , locals ) {
189+ return ( getter ( self , locals ) ) ;
190+ } ,
191+ {
192+ assign :function ( self , value ) {
193+ return setter ( self , ident , value ) ;
194+ }
195+ }
196+ )
191197 } ) ;
192198
193199 if ( methodName ) {
@@ -257,22 +263,18 @@ function parser(text, json, $filter){
257263 value ,
258264 tokens = lex ( text ) ,
259265 assignment = _assignment ,
260- assignable = logicalOR ,
261266 functionCall = _functionCall ,
262267 fieldAccess = _fieldAccess ,
263268 objectIndex = _objectIndex ,
264- filterChain = _filterChain ,
265- functionIdent = _functionIdent ;
269+ filterChain = _filterChain
266270 if ( json ) {
267271 // The extra level of aliasing is here, just in case the lexer misses something, so that
268272 // we prevent any accidental execution in JSON.
269273 assignment = logicalOR ;
270274 functionCall =
271275 fieldAccess =
272276 objectIndex =
273- assignable =
274277 filterChain =
275- functionIdent =
276278 function ( ) { throwError ( "is not valid json" , { text :text , index :0 } ) ; } ;
277279 value = primary ( ) ;
278280 } else {
@@ -328,14 +330,14 @@ function parser(text, json, $filter){
328330 }
329331
330332 function unaryFn ( fn , right ) {
331- return function ( self ) {
332- return fn ( self , right ) ;
333+ return function ( self , locals ) {
334+ return fn ( self , locals , right ) ;
333335 } ;
334336 }
335337
336338 function binaryFn ( left , fn , right ) {
337- return function ( self ) {
338- return fn ( self , left , right ) ;
339+ return function ( self , locals ) {
340+ return fn ( self , locals , left , right ) ;
339341 } ;
340342 }
341343
@@ -353,12 +355,12 @@ function parser(text, json, $filter){
353355 // TODO(size): maybe we should not support multiple statements?
354356 return statements . length == 1
355357 ? statements [ 0 ]
356- : function ( self ) {
358+ : function ( self , locals ) {
357359 var value ;
358360 for ( var i = 0 ; i < statements . length ; i ++ ) {
359361 var statement = statements [ i ] ;
360362 if ( statement )
361- value = statement ( self ) ;
363+ value = statement ( self , locals ) ;
362364 }
363365 return value ;
364366 } ;
@@ -386,10 +388,10 @@ function parser(text, json, $filter){
386388 if ( ( token = expect ( ':' ) ) ) {
387389 argsFn . push ( expression ( ) ) ;
388390 } else {
389- var fnInvoke = function ( self , input ) {
391+ var fnInvoke = function ( self , locals , input ) {
390392 var args = [ input ] ;
391393 for ( var i = 0 ; i < argsFn . length ; i ++ ) {
392- args . push ( argsFn [ i ] ( self ) ) ;
394+ args . push ( argsFn [ i ] ( self , locals ) ) ;
393395 }
394396 return fn . apply ( self , args ) ;
395397 } ;
@@ -414,8 +416,8 @@ function parser(text, json, $filter){
414416 text . substring ( 0 , token . index ) + "] can not be assigned to" , token ) ;
415417 }
416418 right = logicalOR ( ) ;
417- return function ( self ) {
418- return left . assign ( self , right ( self ) ) ;
419+ return function ( self , locals ) {
420+ return left . assign ( self , right ( self , locals ) , locals ) ;
419421 } ;
420422 } else {
421423 return left ;
@@ -546,22 +548,25 @@ function parser(text, json, $filter){
546548 function _fieldAccess ( object ) {
547549 var field = expect ( ) . text ;
548550 var getter = getterFn ( field ) ;
549- return extend ( function ( self ) {
550- return getter ( object ( self ) ) ;
551- } , {
552- assign :function ( self , value ) {
553- return setter ( object ( self ) , field , value ) ;
554- }
555- } ) ;
551+ return extend (
552+ function ( self , locals ) {
553+ return getter ( object ( self , locals ) , locals ) ;
554+ } ,
555+ {
556+ assign :function ( self , value , locals ) {
557+ return setter ( object ( self , locals ) , field , value ) ;
558+ }
559+ }
560+ ) ;
556561 }
557562
558563 function _objectIndex ( obj ) {
559564 var indexFn = expression ( ) ;
560565 consume ( ']' ) ;
561566 return extend (
562- function ( self ) {
563- var o = obj ( self ) ,
564- i = indexFn ( self ) ,
567+ function ( self , locals ) {
568+ var o = obj ( self , locals ) ,
569+ i = indexFn ( self , locals ) ,
565570 v , p ;
566571
567572 if ( ! o ) return undefined ;
@@ -576,8 +581,8 @@ function parser(text, json, $filter){
576581 }
577582 return v ;
578583 } , {
579- assign :function ( self , value ) {
580- return obj ( self ) [ indexFn ( self ) ] = value ;
584+ assign :function ( self , value , locals ) {
585+ return obj ( self , locals ) [ indexFn ( self , locals ) ] = value ;
581586 }
582587 } ) ;
583588 }
@@ -590,14 +595,14 @@ function parser(text, json, $filter){
590595 } while ( expect ( ',' ) ) ;
591596 }
592597 consume ( ')' ) ;
593- return function ( self ) {
598+ return function ( self , locals ) {
594599 var args = [ ] ,
595- context = contextGetter ? contextGetter ( self ) : self ;
600+ context = contextGetter ? contextGetter ( self , locals ) : self ;
596601
597602 for ( var i = 0 ; i < argsFn . length ; i ++ ) {
598- args . push ( argsFn [ i ] ( self ) ) ;
603+ args . push ( argsFn [ i ] ( self , locals ) ) ;
599604 }
600- var fnPtr = fn ( self ) || noop ;
605+ var fnPtr = fn ( self , locals ) || noop ;
601606 // IE stupidity!
602607 return fnPtr . apply
603608 ? fnPtr . apply ( context , args )
@@ -614,10 +619,10 @@ function parser(text, json, $filter){
614619 } while ( expect ( ',' ) ) ;
615620 }
616621 consume ( ']' ) ;
617- return function ( self ) {
622+ return function ( self , locals ) {
618623 var array = [ ] ;
619624 for ( var i = 0 ; i < elementFns . length ; i ++ ) {
620- array . push ( elementFns [ i ] ( self ) ) ;
625+ array . push ( elementFns [ i ] ( self , locals ) ) ;
621626 }
622627 return array ;
623628 } ;
@@ -635,11 +640,11 @@ function parser(text, json, $filter){
635640 } while ( expect ( ',' ) ) ;
636641 }
637642 consume ( '}' ) ;
638- return function ( self ) {
643+ return function ( self , locals ) {
639644 var object = { } ;
640645 for ( var i = 0 ; i < keyValues . length ; i ++ ) {
641646 var keyValue = keyValues [ i ] ;
642- var value = keyValue . value ( self ) ;
647+ var value = keyValue . value ( self , locals ) ;
643648 object [ keyValue . key ] = value ;
644649 }
645650 return object ;
@@ -700,10 +705,14 @@ function getterFn(path) {
700705 if ( fn ) return fn ;
701706
702707 var code = 'var l, fn, p;\n' ;
703- forEach ( path . split ( '.' ) , function ( key ) {
708+ forEach ( path . split ( '.' ) , function ( key , index ) {
704709 code += 'if(!s) return s;\n' +
705710 'l=s;\n' +
706- 's=s' + '["' + key + '"]' + ';\n' +
711+ 's=' + ( index
712+ // we simply direference 's' on any .dot notation
713+ ? 's'
714+ // but if we are first then we check locals firs, and if so read it first
715+ : '((k&&k.hasOwnProperty("' + key + '"))?k:s)' ) + '["' + key + '"]' + ';\n' +
707716 'if (s && s.then) {\n' +
708717 ' if (!("$$v" in s)) {\n' +
709718 ' p=s;\n' +
@@ -714,7 +723,7 @@ function getterFn(path) {
714723 '}\n' ;
715724 } ) ;
716725 code += 'return s;' ;
717- fn = Function ( 's' , code ) ;
726+ fn = Function ( 's' , 'k' , code ) ;
718727 fn . toString = function ( ) { return code ; } ;
719728
720729 return getterFnCache [ path ] = fn ;
0 commit comments