From 8f0dcbab804180828d6859b1340c86cf161209fb Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 23 Mar 2011 09:33:29 -0700 Subject: feat(scope): new and improved scope implementation - Speed improvements (about 4x on flush phase) - Memory improvements (uses no function closures) - Break $eval into $apply, $dispatch, $flush - Introduced $watch and $observe Breaks angular.equals() use === instead of == Breaks angular.scope() does not take parent as first argument Breaks scope.$watch() takes scope as first argument Breaks scope.$set(), scope.$get are removed Breaks scope.$config is removed Breaks $route.onChange callback has not "this" bounded --- src/parser.js | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'src/parser.js') diff --git a/src/parser.js b/src/parser.js index 73733d48..76f9630e 100644 --- a/src/parser.js +++ b/src/parser.js @@ -659,5 +659,116 @@ function parser(text, json){ } } +////////////////////////////////////////////////// +// Parser helper functions +////////////////////////////////////////////////// + +function setter(obj, path, setValue) { + var element = path.split('.'); + for (var i = 0; element.length > 1; i++) { + var key = element.shift(); + var propertyObj = obj[key]; + if (!propertyObj) { + propertyObj = {}; + obj[key] = propertyObj; + } + obj = propertyObj; + } + obj[element.shift()] = setValue; + return setValue; +} + +/** + * Return the value accesible from the object by path. Any undefined traversals are ignored + * @param {Object} obj starting object + * @param {string} path path to traverse + * @param {boolean=true} bindFnToScope + * @returns value as accesbile by path + */ +function getter(obj, path, bindFnToScope) { + if (!path) return obj; + var keys = path.split('.'); + var key; + var lastInstance = obj; + var len = keys.length; + + for (var i = 0; i < len; i++) { + key = keys[i]; + if (obj) { + obj = (lastInstance = obj)[key]; + } + if (isUndefined(obj) && key.charAt(0) == '$') { + var type = angularGlobal.typeOf(lastInstance); + type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; + var fn = type ? type[[key.substring(1)]] : _undefined; + if (fn) { + return obj = bind(lastInstance, fn, lastInstance); + } + } + } + if (!bindFnToScope && isFunction(obj)) { + return bind(lastInstance, obj); + } + return obj; +} + +var getterFnCache = {}, + compileCache = {}, + JS_KEYWORDS = {}; + +forEach( + ("abstract,boolean,break,byte,case,catch,char,class,const,continue,debugger,default," + + "delete,do,double,else,enum,export,extends,false,final,finally,float,for,function,goto," + + "if,implements,import,ininstanceof,intinterface,long,native,new,null,package,private," + + "protected,public,return,short,static,super,switch,synchronized,this,throw,throws," + + "transient,true,try,typeof,var,volatile,void,undefined,while,with").split(/,/), + function(key){ JS_KEYWORDS[key] = true;} +); + +function getterFn(path) { + var fn = getterFnCache[path]; + if (fn) return fn; + + var code = 'var l, fn, t;\n'; + forEach(path.split('.'), function(key) { + key = (JS_KEYWORDS[key]) ? '["' + key + '"]' : '.' + key; + code += 'if(!s) return s;\n' + + 'l=s;\n' + + 's=s' + key + ';\n' + + 'if(typeof s=="function" && !(s instanceof RegExp)) s = function(){ return l' + + key + '.apply(l, arguments); };\n'; + if (key.charAt(1) == '$') { + // special code for super-imposed functions + var name = key.substr(2); + code += 'if(!s) {\n' + + ' t = angular.Global.typeOf(l);\n' + + ' fn = (angular[t.charAt(0).toUpperCase() + t.substring(1)]||{})["' + name + '"];\n' + + ' if (fn) s = function(){ return fn.apply(l, ' + + '[l].concat(Array.prototype.slice.call(arguments, 0, arguments.length))); };\n' + + '}\n'; + } + }); + code += 'return s;'; + fn = Function('s', code); + fn["toString"] = function(){ return code; }; + + return getterFnCache[path] = fn; +} +/////////////////////////////////// +// TODO(misko): Should this function be public? +function compileExpr(expr) { + return parser(expr).statements(); +} + +// TODO(misko): Deprecate? Remove! +// I think that compilation should be a service. +function expressionCompile(exp) { + if (typeof exp === $function) return exp; + var fn = compileCache[exp]; + if (!fn) { + fn = compileCache[exp] = parser(exp).statements(); + } + return fn; +} -- cgit v1.2.3