@@ -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 ( constFunc , name ) {
91+ constFunc . constant = constFunc . literal = constFunc . $$parseShared = true ;
92+ CONSTANTS [ name ] = constFunc ;
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 , parserText ) ;
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 , parserText ) ;
327- }
328- } ) ;
329- }
330-
331- this . tokens . push ( token ) ;
319+ text : ident ,
320+ fn : CONSTANTS [ ident ] || getterFn ( ident , this . options , parserText )
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+ $$parseShared : 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 . $$parseShared = true ;
941937 getterFnCache [ path ] = fn ;
942938 return fn ;
943939}
@@ -1005,6 +1001,21 @@ function $ParseProvider() {
10051001 this . $get = [ '$filter' , '$sniffer' , function ( $filter , $sniffer ) {
10061002 $parseOptions . csp = $sniffer . csp ;
10071003
1004+ function wrapSharedExpression ( exp ) {
1005+ var wrapped = exp ;
1006+
1007+ if ( exp . $$parseShared ) {
1008+ wrapped = function $parseWrapper ( self , locals ) {
1009+ return exp ( self , locals ) ;
1010+ } ;
1011+ wrapped . literal = exp . literal ;
1012+ wrapped . constant = exp . constant ;
1013+ wrapped . assign = exp . assign ;
1014+ }
1015+
1016+ return wrapped ;
1017+ }
1018+
10081019 return function $parse ( exp , interceptorFn ) {
10091020 var parsedExpression , oneTime , cacheKey ;
10101021
@@ -1027,6 +1038,9 @@ function $ParseProvider() {
10271038 if ( parsedExpression . constant ) {
10281039 parsedExpression . $$watchDelegate = constantWatchDelegate ;
10291040 } else if ( oneTime ) {
1041+ //oneTime is not part of the exp passed to the Parser so we may have to
1042+ //wrap the parsedExpression before adding a $$watchDelegate
1043+ parsedExpression = wrapSharedExpression ( parsedExpression ) ;
10301044 parsedExpression . $$watchDelegate = parsedExpression . literal ?
10311045 oneTimeLiteralWatchDelegate : oneTimeWatchDelegate ;
10321046 }
0 commit comments