aboutsummaryrefslogtreecommitdiffstats
path: root/src/parser.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.js')
-rw-r--r--src/parser.js111
1 files changed, 111 insertions, 0 deletions
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;
+}