1
1
'use strict' ;
2
2
3
3
var 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 ; } ,
7
7
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 ) ; } ,
14
14
'=' :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 ) ; }
27
27
} ;
28
28
var ESCAPE = { "n" :"\n" , "f" :"\f" , "r" :"\r" , "t" :"\t" , "v" :"\v" , "'" :"'" , '"' :'"' } ;
29
29
@@ -146,7 +146,7 @@ function lex(text){
146
146
function readIdent ( ) {
147
147
var ident = "" ,
148
148
start = index ,
149
- fn , lastDot , peekIndex , methodName ;
149
+ fn , lastDot , peekIndex , methodName , getter ;
150
150
151
151
while ( index < text . length ) {
152
152
var ch = text . charAt ( index ) ;
@@ -179,15 +179,21 @@ function lex(text){
179
179
}
180
180
181
181
fn = OPERATORS [ ident ] ;
182
+ getter = getterFn ( ident ) ;
182
183
tokens . push ( {
183
184
index :start ,
184
185
text :ident ,
185
186
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
+ )
191
197
} ) ;
192
198
193
199
if ( methodName ) {
@@ -257,22 +263,18 @@ function parser(text, json, $filter){
257
263
value ,
258
264
tokens = lex ( text ) ,
259
265
assignment = _assignment ,
260
- assignable = logicalOR ,
261
266
functionCall = _functionCall ,
262
267
fieldAccess = _fieldAccess ,
263
268
objectIndex = _objectIndex ,
264
- filterChain = _filterChain ,
265
- functionIdent = _functionIdent ;
269
+ filterChain = _filterChain
266
270
if ( json ) {
267
271
// The extra level of aliasing is here, just in case the lexer misses something, so that
268
272
// we prevent any accidental execution in JSON.
269
273
assignment = logicalOR ;
270
274
functionCall =
271
275
fieldAccess =
272
276
objectIndex =
273
- assignable =
274
277
filterChain =
275
- functionIdent =
276
278
function ( ) { throwError ( "is not valid json" , { text :text , index :0 } ) ; } ;
277
279
value = primary ( ) ;
278
280
} else {
@@ -328,14 +330,14 @@ function parser(text, json, $filter){
328
330
}
329
331
330
332
function unaryFn ( fn , right ) {
331
- return function ( self ) {
332
- return fn ( self , right ) ;
333
+ return function ( self , locals ) {
334
+ return fn ( self , locals , right ) ;
333
335
} ;
334
336
}
335
337
336
338
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 ) ;
339
341
} ;
340
342
}
341
343
@@ -353,12 +355,12 @@ function parser(text, json, $filter){
353
355
// TODO(size): maybe we should not support multiple statements?
354
356
return statements . length == 1
355
357
? statements [ 0 ]
356
- : function ( self ) {
358
+ : function ( self , locals ) {
357
359
var value ;
358
360
for ( var i = 0 ; i < statements . length ; i ++ ) {
359
361
var statement = statements [ i ] ;
360
362
if ( statement )
361
- value = statement ( self ) ;
363
+ value = statement ( self , locals ) ;
362
364
}
363
365
return value ;
364
366
} ;
@@ -386,10 +388,10 @@ function parser(text, json, $filter){
386
388
if ( ( token = expect ( ':' ) ) ) {
387
389
argsFn . push ( expression ( ) ) ;
388
390
} else {
389
- var fnInvoke = function ( self , input ) {
391
+ var fnInvoke = function ( self , locals , input ) {
390
392
var args = [ input ] ;
391
393
for ( var i = 0 ; i < argsFn . length ; i ++ ) {
392
- args . push ( argsFn [ i ] ( self ) ) ;
394
+ args . push ( argsFn [ i ] ( self , locals ) ) ;
393
395
}
394
396
return fn . apply ( self , args ) ;
395
397
} ;
@@ -414,8 +416,8 @@ function parser(text, json, $filter){
414
416
text . substring ( 0 , token . index ) + "] can not be assigned to" , token ) ;
415
417
}
416
418
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 ) ;
419
421
} ;
420
422
} else {
421
423
return left ;
@@ -546,22 +548,25 @@ function parser(text, json, $filter){
546
548
function _fieldAccess ( object ) {
547
549
var field = expect ( ) . text ;
548
550
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
+ ) ;
556
561
}
557
562
558
563
function _objectIndex ( obj ) {
559
564
var indexFn = expression ( ) ;
560
565
consume ( ']' ) ;
561
566
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 ) ,
565
570
v , p ;
566
571
567
572
if ( ! o ) return undefined ;
@@ -576,8 +581,8 @@ function parser(text, json, $filter){
576
581
}
577
582
return v ;
578
583
} , {
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 ;
581
586
}
582
587
} ) ;
583
588
}
@@ -590,14 +595,14 @@ function parser(text, json, $filter){
590
595
} while ( expect ( ',' ) ) ;
591
596
}
592
597
consume ( ')' ) ;
593
- return function ( self ) {
598
+ return function ( self , locals ) {
594
599
var args = [ ] ,
595
- context = contextGetter ? contextGetter ( self ) : self ;
600
+ context = contextGetter ? contextGetter ( self , locals ) : self ;
596
601
597
602
for ( var i = 0 ; i < argsFn . length ; i ++ ) {
598
- args . push ( argsFn [ i ] ( self ) ) ;
603
+ args . push ( argsFn [ i ] ( self , locals ) ) ;
599
604
}
600
- var fnPtr = fn ( self ) || noop ;
605
+ var fnPtr = fn ( self , locals ) || noop ;
601
606
// IE stupidity!
602
607
return fnPtr . apply
603
608
? fnPtr . apply ( context , args )
@@ -614,10 +619,10 @@ function parser(text, json, $filter){
614
619
} while ( expect ( ',' ) ) ;
615
620
}
616
621
consume ( ']' ) ;
617
- return function ( self ) {
622
+ return function ( self , locals ) {
618
623
var array = [ ] ;
619
624
for ( var i = 0 ; i < elementFns . length ; i ++ ) {
620
- array . push ( elementFns [ i ] ( self ) ) ;
625
+ array . push ( elementFns [ i ] ( self , locals ) ) ;
621
626
}
622
627
return array ;
623
628
} ;
@@ -635,11 +640,11 @@ function parser(text, json, $filter){
635
640
} while ( expect ( ',' ) ) ;
636
641
}
637
642
consume ( '}' ) ;
638
- return function ( self ) {
643
+ return function ( self , locals ) {
639
644
var object = { } ;
640
645
for ( var i = 0 ; i < keyValues . length ; i ++ ) {
641
646
var keyValue = keyValues [ i ] ;
642
- var value = keyValue . value ( self ) ;
647
+ var value = keyValue . value ( self , locals ) ;
643
648
object [ keyValue . key ] = value ;
644
649
}
645
650
return object ;
@@ -700,10 +705,14 @@ function getterFn(path) {
700
705
if ( fn ) return fn ;
701
706
702
707
var code = 'var l, fn, p;\n' ;
703
- forEach ( path . split ( '.' ) , function ( key ) {
708
+ forEach ( path . split ( '.' ) , function ( key , index ) {
704
709
code += 'if(!s) return s;\n' +
705
710
'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' +
707
716
'if (s && s.then) {\n' +
708
717
' if (!("$$v" in s)) {\n' +
709
718
' p=s;\n' +
@@ -714,7 +723,7 @@ function getterFn(path) {
714
723
'}\n' ;
715
724
} ) ;
716
725
code += 'return s;' ;
717
- fn = Function ( 's' , code ) ;
726
+ fn = Function ( 's' , 'k' , code ) ;
718
727
fn . toString = function ( ) { return code ; } ;
719
728
720
729
return getterFnCache [ path ] = fn ;
0 commit comments