14ee2ad04344446e610172a0e73949212923014dfSebastian Redl// Copyright 2006 Google Inc. 22cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// 32cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// Licensed under the Apache License, Version 2.0 (the "License"); 42cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// you may not use this file except in compliance with the License. 52cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// You may obtain a copy of the License at 62cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// 72cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// http://www.apache.org/licenses/LICENSE-2.0 82cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// 92cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// Unless required by applicable law or agreed to in writing, software 10a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl// distributed under the License is distributed on an "AS IS" BASIS, 112cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// implied. See the License for the specific language governing 132cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor// permissions and limitations under the License. 147faa2ec03a7ef120ac165bb45b6c70a8b20c9f1cSebastian Redl/** 150eca89e9890db4d8336ce762a5b359a1d58ca02bArgyrios Kyrtzidis * Author: Steffen Meschkat <mesch@google.com> 16e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor * 17e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor * @fileoverview This class is used to evaluate expressions in a local 182cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * context. Used by JstProcessor. 192cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 202cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 212a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall 2289eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis/** 230b7489194f9f89fac39d57211c1e7953ae50251fDouglas Gregor * Names of special variables defined by the jstemplate evaluation 247a1fad38256eb4c5129359be85ba1ea1678eb5c9John McCall * context. These can be used in js expression in jstemplate 252cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * attributes. 26a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall */ 276ab7cd853e9c15cf986a8a7c3db1f8d20e275409Sebastian Redlvar VAR_index = '$index'; 287c5d24efcd2e505b5739f7def08dfe25ce59a1b2Chris Lattnervar VAR_count = '$count'; 296a5a23f8e7fb65e028c8092bc1d1a1d9dfe2e9bcDouglas Gregorvar VAR_this = '$this'; 307c5d24efcd2e505b5739f7def08dfe25ce59a1b2Chris Lattnervar VAR_context = '$context'; 3183d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroffvar VAR_top = '$top'; 3214f79002e58556798e86168c63e48d533287eda5Douglas Gregor 3310e286aa8d39fb51a21412850265d9dae74613eeChris Lattner 343251ceb90b3fec68e86d6dcfa58836e20a7205c3Douglas Gregor/** 3514f79002e58556798e86168c63e48d533287eda5Douglas Gregor * The name of the global variable which holds the value to be returned if 36bd94500d3aa60092fb0f1e90f53fb0d03fa502a8Douglas Gregor * context evaluation results in an error. 372bec0410d268779f601bd509e0302a500af7ac6aDouglas Gregor * Use JsEvalContext.setGlobal(GLOB_default, value) to set this. 38ab41e63821dc60ad144d0684df8d79a9eef86b75Douglas Gregor */ 390a0d2b179085a52c10402feebeb6db8b4d96a140Douglas Gregorvar GLOB_default = '$default'; 4017fc223395d51be582fc666bb6ea21bd1dff26dcDouglas Gregor 4117fc223395d51be582fc666bb6ea21bd1dff26dcDouglas Gregor 422596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar/** 432cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * Un-inlined literals, to avoid object creation in IE6. TODO(mesch): 44fbfd180495e7800975c6d9bdc6d24e706ef70e34Michael J. Spencer * So far, these are only used here, but we could use them thoughout 4514f79002e58556798e86168c63e48d533287eda5Douglas Gregor * the code and thus move them to constants.js. 4603013fa9a0bf1ef4b907f5fec006c8f4000fdd21Michael J. Spencer */ 47f62d43d2afe1960755a1b5813cae1e5983bcac1bDouglas Gregorvar CHAR_colon = ':'; 483c304bd9ec2b4611572d4cbae9e1727bbecb5dc9Chris Lattnervar REGEXP_semicolon = /\s*;\s*/; 49cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor 50f62d43d2afe1960755a1b5813cae1e5983bcac1bDouglas Gregor 512cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor/** 528538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * See constructor_() 532cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {Object|null} opt_data 54ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl * @param {Object} opt_parent 555f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner * @constructor 565f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner */ 575f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerfunction JsEvalContext(opt_data, opt_parent) { 586e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer this.constructor_.apply(this, arguments); 59ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl} 606e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer 616e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer/** 625f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner * Context for processing a jstemplate. The context contains a context 635f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner * object, whose properties can be referred to in jstemplate 646e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer * expressions, and it holds the locally defined variables. 65ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl * 66ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl * @param {Object|null} opt_data The context object. Null if no context. 672cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 682cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {Object} opt_parent The parent context, from which local 692cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * variables are inherited. Normally the context object of the parent 7012b1c7615d4f9a2edc544be499f895f16ac100edChris Lattner * context is the object whose property the parent object is. Null for the 712cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * context of the root object. 723397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl */ 73a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian RedlJsEvalContext.prototype.constructor_ = function(opt_data, opt_parent) { 7489eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis var me = this; 752cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 762cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor /** 772cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * The context for variable definitions in which the jstemplate 788538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * expressions are evaluated. Other than for the local context, 792cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * which replaces the parent context, variable definitions of the 8089eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis * parent are inherited. The special variable $this points to data_. 818538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * 822cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * If this instance is recycled from the cache, then the property is 832cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * already initialized. 842cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 852cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @type {Object} 862cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 872cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor if (!me.vars_) { 882cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor me.vars_ = {}; 892cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor } 902cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor if (opt_parent) { 912cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // If there is a parent node, inherit local variables from the 922cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // parent. 933397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl copyProperties(me.vars_, opt_parent.vars_); 94b219cfc4d75f0a03630b7c4509ef791b7e97b2c8David Blaikie } else { 952cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // If a root node, inherit global symbols. Since every parent 962cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // chain has a root with no parent, global variables will be 973397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl // present in the case above too. This means that globals can be 982cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // overridden by locals, as it should be. 998538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl copyProperties(me.vars_, JsEvalContext.globals_); 1002cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor } 1012cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 1023397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl /** 1032cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * The current context object is assigned to the special variable 1048538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * $this so it is possible to use it in expressions. 1052cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @type Object 1062cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 1073397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl me.vars_[VAR_this] = opt_data; 1081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1098538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl /** 1102cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * The entire context structure is exposed as a variable so it can be 1112cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * passed to javascript invocations through jseval. 1123397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl */ 113df1550fc59b51681d37225934fe4e3acac321621Richard Smith me.vars_[VAR_context] = me; 114df1550fc59b51681d37225934fe4e3acac321621Richard Smith 1158538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl /** 1162cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * The local context of the input data in which the jstemplate 1172cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * expressions are evaluated. Notice that this is usually an Object, 1183397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * but it can also be a scalar value (and then still the expression 119df1550fc59b51681d37225934fe4e3acac321621Richard Smith * $this can be used to refer to it). Notice this can even be value, 1208538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * undefined or null. Hence, we have to protect jsexec() from using 1212cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * undefined or null, yet we want $this to reflect the true value of 1222cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * the current context. Thus we assign the original value to $this, 1233397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * above, but for the expression context we replace null and 1241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * undefined by the empty string. 1251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * 1268538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * @type {Object|null} 1272cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 1282cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor me.data_ = getDefaultObject(opt_data, STRING_empty); 1293397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl 1302cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor if (!opt_parent) { 1312cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // If this is a top-level context, create a variable reference to the data 1320953e767ff7817f97b3ab20896b229891eeff45bJohn McCall // to allow for accessing top-level properties of the original context 1332cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor // data from child contexts. 1342cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor me.vars_[VAR_top] = me.data_; 1353397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl } 1362cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}; 1372cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 1388538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl 1392cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor/** 1402cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * A map of globally defined symbols. Every instance of JsExprContext 1413397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * inherits them in its vars_. 1422cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @type Object 1438538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl */ 1442cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorJsEvalContext.globals_ = {} 1452cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 1463397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl 1472cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor/** 1487e7eb3da052a6d80ddf2377cab0384c798f73f75Douglas Gregor * Sets a global symbol. It will be available like a variable in every 1497e7eb3da052a6d80ddf2377cab0384c798f73f75Douglas Gregor * JsEvalContext instance. This is intended mainly to register 150c9490c000f515c29f200a1215328d8ab9a0f3818Douglas Gregor * immutable global objects, such as functions, at load time, and not 1518538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * to add global data at runtime. I.e. the same objections as to 1522cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * global variables in general apply also here. (Hence the name 1532cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * "global", and not "global var".) 1543397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * @param {string} name 1552cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {Object|null} value 1562cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 157e86d78cf4754a6aef2cf9a33d847aa15338e276fBob WilsonJsEvalContext.setGlobal = function(name, value) { 1588538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl JsEvalContext.globals_[name] = value; 1592cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}; 1602cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 1613397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl 1622cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor/** 1638538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * Set the default value to be returned if context evaluation results in an 1642cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * error. (This can occur if a non-existent value was requested). 1652cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 1663397c5570369f19b2d6c52e898f708d75ceede1fSebastian RedlJsEvalContext.setGlobal(GLOB_default, null); 1672cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 168264ba48dc98f3f843935a485d5b086f7e0fdc4f1Rafael Espindola 169264ba48dc98f3f843935a485d5b086f7e0fdc4f1Rafael Espindola/** 170a49218e17bcbb1acde0245773173e2c0c42f4f19Eli Friedman * A cache to reuse JsEvalContext instances. (IE6 perf) 171425ef72306d4ff6b3698b744353e5f0e56b4b884Rafael Espindola * 172ab8bbf4ebd3e3e6eab913cb044772a62b7581941Douglas Gregor * @type Array.<JsEvalContext> 173264ba48dc98f3f843935a485d5b086f7e0fdc4f1Rafael Espindola */ 174f85e193739c953358c865005855253af4f68a497John McCallJsEvalContext.recycledInstances_ = []; 1752cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 1762cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 1773397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl/** 1782cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * A factory to create a JsEvalContext instance, possibly reusing 1798538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * one from recycledInstances_. (IE6 perf) 1802cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 1812cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {Object} opt_data 1823397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * @param {JsEvalContext} opt_parent 1832cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @return {JsEvalContext} 1842cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */ 1852cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorJsEvalContext.create = function(opt_data, opt_parent) { 1862cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor if (jsLength(JsEvalContext.recycledInstances_) > 0) { 1872cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor var instance = JsEvalContext.recycledInstances_.pop(); 1882cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor JsEvalContext.call(instance, opt_data, opt_parent); 189c938c1668b4fd12af154e965dd935a89e4801a70Douglas Gregor return instance; 19060618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl } else { 19160618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl return new JsEvalContext(opt_data, opt_parent); 19260618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl } 19360618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl}; 19460618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl 19560618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl 19660618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl/** 19760618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl * Recycle a used JsEvalContext instance, so we can avoid creating one 1988538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * the next time we need one. (IE6 perf) 1992cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 2002cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {JsEvalContext} instance 2013397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl */ 202ed97649e9574b9d854fa4d6109c9333ae0993554John McCallJsEvalContext.recycle = function(instance) { 2038538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl for (var i in instance.vars_) { 204ed97649e9574b9d854fa4d6109c9333ae0993554John McCall // NOTE(mesch): We avoid object creation here. (IE6 perf) 205ed97649e9574b9d854fa4d6109c9333ae0993554John McCall delete instance.vars_[i]; 2063397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl } 2072cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor instance.data_ = null; 2089763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis JsEvalContext.recycledInstances_.push(instance); 2099763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis}; 2108538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl 2112cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 2122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor/** 2133397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * Executes a function created using jsEvalToFunction() in the context 214c9490c000f515c29f200a1215328d8ab9a0f3818Douglas Gregor * of vars, data, and template. 2158538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * 2162cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {Function} exprFunction A javascript function created from 2172cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * a jstemplate attribute value. 2183397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * 2192cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {Element} template DOM node of the template. 2208538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * 2212cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @return {Object|null} The value of the expression from which 2222cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * exprFunction was created in the current js expression context and 2233397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * the context of template. 224395b475a4474f1c7574d927ad142ca0c7997cbcaAnders Carlsson */ 2258538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian RedlJsEvalContext.prototype.jsexec = function(exprFunction, template) { 226395b475a4474f1c7574d927ad142ca0c7997cbcaAnders Carlsson try { 227395b475a4474f1c7574d927ad142ca0c7997cbcaAnders Carlsson return exprFunction.call(template, this.vars_, this.data_); 228ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt } catch (e) { 229ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt log('jsexec EXCEPTION: ' + e + ' at ' + template + 230ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt ' with ' + exprFunction); 231ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt return JsEvalContext.globals_[GLOB_default]; 232ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt } 233ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt}; 234ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt 23534b41d939a1328f484511c6002ba2456db879a29Richard Smith 23634b41d939a1328f484511c6002ba2456db879a29Richard Smith/** 23734b41d939a1328f484511c6002ba2456db879a29Richard Smith * Clones the current context for a new context object. The cloned 23834b41d939a1328f484511c6002ba2456db879a29Richard Smith * context has the data object as its context object and the current 23934b41d939a1328f484511c6002ba2456db879a29Richard Smith * context as its parent context. It also sets the $index variable to 2403397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * the given value. This value usually is the position of the data 241be191100e034b23a3e13053757a57b7f5068c24aArgyrios Kyrtzidis * object in a list for which a template is instantiated multiply. 2422cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 2431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * @param {Object} data The new context object. 2442cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 2452cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {number} index Position of the new context when multiply 2462cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * instantiated. (See implementation of jstSelect().) 2473397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * 2482cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @param {number} count The total number of contexts that were multiply 2498538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * instantiated. (See implementation of jstSelect().) 2502cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 2512cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * @return {JsEvalContext} 2523397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl */ 2532cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorJsEvalContext.prototype.clone = function(data, index, count) { 2548538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl var ret = JsEvalContext.create(data, this); 2552cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor ret.setVariable(VAR_index, index); 2562cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor ret.setVariable(VAR_count, count); 2579d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall return ret; 2589d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall}; 2599d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall 2609d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall 2619d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall/** 2629d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall * Binds a local variable to the given value. If set from jstemplate 2639d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall * jsvalue expressions, variable names must start with $, but in the 2641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * API they only have to be valid javascript identifier. 2653397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * 26649a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall * @param {string} name 26749a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall * 26849a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall * @param {Object?} value 2698538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl */ 27049a832bd499d6f61c23655f1fac99f0dd229756eJohn McCallJsEvalContext.prototype.setVariable = function(name, value) { 27149a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall this.vars_[name] = value; 27249a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall}; 273c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor 274c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor 275c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor/** 276c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor * Returns the value bound to the local variable of the given name, or 277c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor * undefined if it wasn't set. There is no way to distinguish a 278c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor * variable that wasn't set from a variable that was set to 279c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor * undefined. Used mostly for testing. 280c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor * 2813397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * @param {string} name 2822cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 283be191100e034b23a3e13053757a57b7f5068c24aArgyrios Kyrtzidis * @return {Object?} value 28490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis */ 28590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios KyrtzidisJsEvalContext.prototype.getVariable = function(name) { 28690b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis return this.vars_[name]; 28790b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis}; 28890b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis 2893e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith 2903e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith/** 2919763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis * Evaluates a string expression within the scope of this context 2929763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis * and returns the result. 2938538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * 29490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * @param {string} expr A javascript expression 29590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * @param {Element} opt_template An optional node to serve as "this" 29690b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * 2973397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * @return {Object?} value 298ae8b17f1d5d303af53db5a4f4a375ea6b9356566Argyrios Kyrtzidis */ 299ae8b17f1d5d303af53db5a4f4a375ea6b9356566Argyrios KyrtzidisJsEvalContext.prototype.evalExpression = function(expr, opt_template) { 300ae8b17f1d5d303af53db5a4f4a375ea6b9356566Argyrios Kyrtzidis var exprFunction = jsEvalToFunction(expr); 3018538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl return this.jsexec(exprFunction, opt_template); 30290b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis}; 30390b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis 30490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis 3053397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl/** 30690b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * Uninlined string literals for jsEvalToFunction() (IE6 perf). 30790b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis */ 308b219cfc4d75f0a03630b7c4509ef791b7e97b2c8David Blaikievar STRING_a = 'a_'; 30990b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidisvar STRING_b = 'b_'; 31090b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidisvar STRING_with = 'with (a_) with (b_) return '; 31190b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis 3123397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl 31390b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis/** 31490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * Cache for jsEvalToFunction results. 31590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * @type Object 3164fb86f8c4585e53c21c847ad3de9e3b2de123cd9Chandler Carruth */ 3178538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian RedlJsEvalContext.evalToFunctionCache_ = {}; 31890b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis 31990b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis 32090b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis/** 3213397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * Evaluates the given expression as the body of a function that takes 3228dfbd8b252ba4e6cf4b7a3422f6ef0ca21312dfeArgyrios Kyrtzidis * vars and data as arguments. Since the resulting function depends 3238dfbd8b252ba4e6cf4b7a3422f6ef0ca21312dfeArgyrios Kyrtzidis * only on expr, we cache the result so we save some Function 3248dfbd8b252ba4e6cf4b7a3422f6ef0ca21312dfeArgyrios Kyrtzidis * invocations, and some object creations in IE6. 325f48d45e3e36c132bdee3373beec4e8b19ae3f9c4Argyrios Kyrtzidis * 326f48d45e3e36c132bdee3373beec4e8b19ae3f9c4Argyrios Kyrtzidis * @param {string} expr A javascript expression. 327f48d45e3e36c132bdee3373beec4e8b19ae3f9c4Argyrios Kyrtzidis * 3288538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * @return {Function} A function that returns the value of expr in the 32990b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis * context of vars and data. 33090b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis */ 33190b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidisfunction jsEvalToFunction(expr) { 3323397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl if (!JsEvalContext.evalToFunctionCache_[expr]) { 33390b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis try { 3343acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis // NOTE(mesch): The Function constructor is faster than eval(). 3353acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis JsEvalContext.evalToFunctionCache_[expr] = 3363acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis new Function(STRING_a, STRING_b, STRING_with + expr); 3373acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis } catch (e) { 3383acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis log('jsEvalToFunction (' + expr + ') EXCEPTION ' + e); 3393acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis } 3403acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis } 3418538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl return JsEvalContext.evalToFunctionCache_[expr]; 3422cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor} 3432cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor 3447536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor 3457536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor/** 346cded4f649cd4b7ba7d461c25c6482ef52b8d3a2aDouglas Gregor * Evaluates the given expression to itself. This is meant to pass 347cded4f649cd4b7ba7d461c25c6482ef52b8d3a2aDouglas Gregor * through string attribute values. 348cded4f649cd4b7ba7d461c25c6482ef52b8d3a2aDouglas Gregor * 349cded4f649cd4b7ba7d461c25c6482ef52b8d3a2aDouglas Gregor * @param {string} expr 3507536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor * 3517536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor * @return {string} 3527536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor */ 353075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnarafunction jsEvalToSelf(expr) { 354075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnara return expr; 355075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnara} 356075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnara 357075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnara 3583397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl/** 359465d41b92b2c862f3062c412a0538db65c6a2661Abramo Bagnara * Parses the value of the jsvalues attribute in jstemplates: splits 3603acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis * it up into a map of labels and expressions, and creates functions 3613acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis * from the expressions that are suitable for execution by 3628538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl * JsEvalContext.jsexec(). All that is returned as a flattened array 3632cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * of pairs of a String and a Function. 3642cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * 3653397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl * @param {string} expr 3663cb0ebd5f76abcb776f7cb4062bd79e3268c0dc4John McCall * 36731f17ecbef57b5679c017c375db330546b7b5145John McCall * @return {Array} 3688538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl */ 3693cb0ebd5f76abcb776f7cb4062bd79e3268c0dc4John McCallfunction jsEvalToValues(expr) { 3703cb0ebd5f76abcb776f7cb4062bd79e3268c0dc4John McCall // TODO(mesch): It is insufficient to split the values by simply 3713397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl // finding semi-colons, as the semi-colon may be part of a string 372deacbdca554298ccdf636f19c6094a8825ec6b34Douglas Gregor // constant or escaped. 3738538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl var ret = []; 374c12c5bba6ceb6acd4e51e7a0fc03257da9cfd44eJohn McCall var values = expr.split(REGEXP_semicolon); 375c12c5bba6ceb6acd4e51e7a0fc03257da9cfd44eJohn McCall for (var i = 0, I = jsLength(values); i < I; ++i) { 3763397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl var colon = values[i].indexOf(CHAR_colon); 377c12c5bba6ceb6acd4e51e7a0fc03257da9cfd44eJohn McCall if (colon < 0) { 3782cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor continue; 379c12c5bba6ceb6acd4e51e7a0fc03257da9cfd44eJohn McCall } 380446ee4eb4fc4c705a59365252df7a5c253daafa1Steve Naroff var label = stringTrim(values[i].substr(0, colon)); 381446ee4eb4fc4c705a59365252df7a5c253daafa1Steve Naroff var value = jsEvalToFunction(values[i].substr(colon + 1)); 3828538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl ret.push(label, value); 3832cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor } 3842cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor return ret; 385d1b3c2dd5bc1f3103bee6137957aa7c5f8f2f0bcSteve Naroff} 3863397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl 3871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3888538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl/** 3892cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * Parses the value of the jseval attribute of jstemplates: splits it 3902cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor * up into a list of expressions, and creates functions from the 391b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman * expressions that are suitable for execution by 392b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman * JsEvalContext.jsexec(). All that is returned as an Array of 393b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman * Function. 394b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman * 395b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman * @param {string} expr 396b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman * 397a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall * @return {Array.<Function>} 398a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall */ 399a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCallfunction jsEvalToExpressions(expr) { 400a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl var ret = []; 40189eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis var values = expr.split(REGEXP_semicolon); 402a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall for (var i = 0, I = jsLength(values); i < I; ++i) { 403a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall if (values[i]) { 40489eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis var value = jsEvalToFunction(values[i]); 405a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall ret.push(value); 406a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall } 40751bd803fbdade51d674598ed45da3d54190a656cJohn McCall } 408a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall return ret; 40951bd803fbdade51d674598ed45da3d54190a656cJohn McCall} 410a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall