@@ -80,12 +80,21 @@ function ensureSafeFunction(obj, fullExpression) {
8080 }
8181}
8282
83+ //Keyword constants
84+ var CONSTANTS = createMap ( ) ;
85+ forEach ( {
86+ 'null' : function ( ) { return null ; } ,
87+ 'true' : function ( ) { return true ; } ,
88+ 'false' : function ( ) { return false ; } ,
89+ 'undefined' : function ( ) { }
90+ } , function ( constantGetter , name ) {
91+ constantGetter . constant = constantGetter . literal = constantGetter . sharedGetter = true ;
92+ CONSTANTS [ name ] = constantGetter ;
93+ } ) ;
94+
95+ //Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
8396var OPERATORS = extend ( createMap ( ) , {
8497 /* jshint bitwise : false */
85- 'null' :function ( ) { return null ; } ,
86- 'true' :function ( ) { return true ; } ,
87- 'false' :function ( ) { return false ; } ,
88- undefined :noop ,
8998 '+' :function ( self , locals , a , b ) {
9099 a = a ( self , locals ) ; b = b ( self , locals ) ;
91100 if ( isDefined ( a ) ) {
@@ -305,30 +314,11 @@ Lexer.prototype = {
305314 }
306315 }
307316
308-
309- var token = {
317+ this . tokens . push ( {
310318 index : start ,
311- text : ident
312- } ;
313-
314- var fn = OPERATORS [ ident ] ;
315-
316- if ( fn ) {
317- token . fn = fn ;
318- token . constant = true ;
319- } else {
320- var getter = getterFn ( ident , this . options , expression ) ;
321- // TODO(perf): consider exposing the getter reference
322- token . fn = extend ( function $parsePathGetter ( self , locals ) {
323- return getter ( self , locals ) ;
324- } , {
325- assign : function ( self , value ) {
326- return setter ( self , ident , value , expression ) ;
327- }
328- } ) ;
329- }
330-
331- this . tokens . push ( token ) ;
319+ text : ident ,
320+ fn : CONSTANTS [ ident ] || getterFn ( ident , this . options , expression )
321+ } ) ;
332322
333323 if ( methodName ) {
334324 this . tokens . push ( {
@@ -397,6 +387,7 @@ var Parser = function (lexer, $filter, options) {
397387Parser . ZERO = extend ( function ( ) {
398388 return 0 ;
399389} , {
390+ sharedGetter : true ,
400391 constant : true
401392} ) ;
402393
@@ -935,9 +926,14 @@ function getterFn(path, options, fullExp) {
935926 var evaledFnGetter = new Function ( 's' , 'l' , code ) ; // s=scope, l=locals
936927 /* jshint +W054 */
937928 evaledFnGetter . toString = valueFn ( code ) ;
929+ evaledFnGetter . assign = function ( self , value ) {
930+ return setter ( self , path , value , path ) ;
931+ } ;
932+
938933 fn = evaledFnGetter ;
939934 }
940935
936+ fn . sharedGetter = true ;
941937 getterFnCache [ path ] = fn ;
942938 return fn ;
943939}
@@ -1004,6 +1000,21 @@ function $ParseProvider() {
10041000 this . $get = [ '$filter' , '$sniffer' , function ( $filter , $sniffer ) {
10051001 $parseOptions . csp = $sniffer . csp ;
10061002
1003+ function wrapSharedExpression ( exp ) {
1004+ var wrapped = exp ;
1005+
1006+ if ( exp . sharedGetter ) {
1007+ wrapped = function $parseWrapper ( self , locals ) {
1008+ return exp ( self , locals ) ;
1009+ } ;
1010+ wrapped . literal = exp . literal ;
1011+ wrapped . constant = exp . constant ;
1012+ wrapped . assign = exp . assign ;
1013+ }
1014+
1015+ return wrapped ;
1016+ }
1017+
10071018 return function $parse ( exp , interceptorFn ) {
10081019 var parsedExpression , oneTime , cacheKey ;
10091020
@@ -1026,6 +1037,9 @@ function $ParseProvider() {
10261037 if ( parsedExpression . constant ) {
10271038 parsedExpression . $$watchDelegate = constantWatchDelegate ;
10281039 } else if ( oneTime ) {
1040+ //oneTime is not part of the exp passed to the Parser so we may have to
1041+ //wrap the parsedExpression before adding a $$watchDelegate
1042+ parsedExpression = wrapSharedExpression ( parsedExpression ) ;
10291043 parsedExpression . $$watchDelegate = parsedExpression . literal ?
10301044 oneTimeLiteralWatchDelegate : oneTimeWatchDelegate ;
10311045 }
0 commit comments