docs: function compileExpression(expr, filter, dependencies) {
  	// console.log('xpr parse : ', expr);
  	var total = expr + filter;
  	if (cacheXpr[total]) {
  		dependencies.push.apply(dependencies, cacheXpr[total].dependencies);
  		return cacheXpr[total].func;
  	}
  	var dep = [],
  		exprReplaced = expr.replace(replacementRegExp, function(whole) {
  			if (whole == 'true' || whole == 'false' ||  whole == 'null')
  				return whole;
  			switch (whole[0]) {
  				case '"':
  				case "'":
  					return whole;
  				case '$':
  					if (whole[1] === '.')
  						return '__global' + whole.substring(1);
  				default:
  					if (whole[whole.length - 1] === '(') { // function call
  						dep.push(whole.substring(0, whole.length - 1));
  						return '__context.data.' + whole;
  					} else { // simple path to var
  						dep.push(whole);
  						// we use indirect value retrieval to avoid throw if path provides null or undefined somewhere
  						return '__context.get(["' + whole.split('.').join('","') + '"])';
  					}
  			}
  		});
  	// console.log('xpr parsing res : ', expr);
  	dependencies.push.apply(dependencies, dep);
  
  	var func = new Function("__context", "__global", "return " + exprReplaced + ";");
  	if (!filter) {
  		cacheXpr[total] = {
  			func: func,
  			dependencies: dep
  		};
  		if (Interpolable.debug)
  			func.expression = expr;
  		return func;
  	}
  	// produce filter 
  	var fltr = new Function('Filter', 'return new Filter().' + filter)(Filter);
  	// wrap expr func with filter
  	var f = function(context, global) {
  		return fltr.call(context, func.call(this, context, global));
  	};
  	if (Interpolable.debug)
  		f.expression = expr;
  	cacheXpr[total] = {
  		func: f,
  		dependencies: dep
  	};
  	return f;
  }