📄 function.js
字号:
var expressionString = expressionArray.join(isc.emptyString); var theFunc; try { theFunc = isc._makeFunction(variables, expressionString); } catch (e) { this.logWarn("invalid code: " + expressionString + " generated from action: " + this.echo(expression)); theFunc = new Function(); } theFunc.iscAction = expression; return theFunc; } var complexIdStartChars = "swirfv"; // if variables passed in as an array of strings, // convert to a single string of vars separated by commas. // if (isc.isAn.Array(variables)) { variables = variables.join(); } var isSimpleExpression = true; // loop through expression character by character. if there is any // indication that it contains more than one statement or a complex // statement, set isSimpleExpression to false and break. var i = 0; // character index. var commentDelimiters = this._commentDelimeters; var stringDelimiters = this._stringDelimeters; // strings that identify that a string is more than a simple expression var complexIdentifiers = this._complexIdentifiers; // the set of characters that can end a line while allowing a statement to continue onto the // next line var multiLineDelimiters = this._multiLineDelimeters; // keeps track of whether we've seen a semicolon. Once we've seen a semicolon, anything // other than whitespace and comments indicates a multi-statement expression var commentsOnly = false; // set up some variables to avoid a bunch of string allocation during loops var nullString = isc._emptyString, commentStart = isc.slash, eol = "\n", backslash = "\\", plusSign = "+", semicolon = isc.semi; // keeps track of the last non-whitespace character, // so we know what it was when we get to the end of a line. var lastChar = nullString; // keeps track of the next non-whitespace character. var nextChar = nullString; // loop through each character of the expression while (i < expression.length) { var currentChar = expression.charAt(i); // check if we're in a comment by seeing if the current characters match any comment // openers if (currentChar == commentStart) { for (var j = 0; j < commentDelimiters.length; j++) { var delimiterSet = commentDelimiters[j], opener = delimiterSet[0], closer = delimiterSet[1] ; //if (expression.substring(i, i + opener.length) == opener) { if (expression.indexOf(opener, i) == i) { // we're in a comment.. skip until we find the comment closer var k = i + opener.length; while (k < expression.length) { if (expression.substring(k, k + closer.length) == closer) { k = k + closer.length; break; } k++; } i = k; lastChar = nullString; nextChar = this._getNextNonWhitespaceChar(expression, i); } } } // we've seen a semicolon. From here on, if we find anything other than a comment or // whitespace, we've got a complex expression if (commentsOnly) { // if we only have whitespace until the end, we can break now. if (nextChar == nullString) { break; } else { if (isc.isA.WhitespaceChar(currentChar)) { i++; continue; } else { isSimpleExpression = false; break; } } } // check for the beginning of string for (var j = 0; j < stringDelimiters.length; j++) { var delim = stringDelimiters[j] if (currentChar == delim) { // we're in a string; find the next unquoted delimeter of the same kind var k = i + 1; while (k < expression.length) { if (expression.charAt(k) == backslash) k = k + 2; // skip over escapes if (expression.charAt(k) == delim) { k++; break; } k++; } i = k; lastChar = delim.charAt(0); nextChar = this._getNextNonWhitespaceChar(expression, i); } } // check if we've reached the end of a line if (currentChar == eol) { // see if the last character on the line is one that would allow the statement to // continue onto another line var isMLD = false; for (var j = 0; j < multiLineDelimiters.length; j++) { if (lastChar == multiLineDelimiters[j]) { isMLD = true; break; } } if (isMLD || nextChar == plusSign) { lastChar = nullString; } else { // the last character on this line closed a statement, and there's more // characters, so this has to be a multi-statement expression isSimpleExpression = false; break; } } // look for semicolon if (currentChar == semicolon) { // set the commentsOnly flag to switch modes: from here on, if we find anything // other than a comment or whitespace, we've got a complex expression commentsOnly = true; } // check for keywords that indicate that this is not a simple expression // Note: There's a bug in string.charAt() in IE4 whereby a negative index will // return the first char of the string. // Therefore explicitly check whether the keyword is present and either at the // beginning or end of the string, or delimited by non AlphaNumeric chars. // (IE: it is the keyword, not just a substring of a non-keyword) // _complexIdentifiers : ["switch", "while", "if", "return", "for", "var"], if (complexIdStartChars.indexOf(currentChar) != -1) { for (var j = 0; j < complexIdentifiers.length; j++) { var word = complexIdentifiers[j], length = word.length; if ( // Don't check if there are not enough characters for the keyword (i + length <= expression.length) && // Is the keyword present? (expression.substring(i, i+length) == word) && // Is it at the end of the string, or followed by a non Alpha char? (i + length == expression.length || !isc.isA.AlphaNumericChar(expression.charAt(i + length))) && // Is it at the beginning of the string, or preceded by a non Alpha char? (i == 0 || !isc.isA.AlphaNumericChar(expression.charAt(i - 1))) ) { isSimpleExpression = false; break; } } } // if the current char isn't whitespace, set it as the last non-whitespace char if (!isc.isA.WhitespaceChar(currentChar)) lastChar = currentChar; // increment i++; // set up a new nextChar nextChar = this._getNextNonWhitespaceChar(expression, i); } if (isSimpleExpression) { expression = "return " + expression; } // add a comment (if one was passed in) to the function // this lets us label the functions if we want to if (comment) expression = "/" + "/" + comment + "\r\n" + expression; // now create the new function and return it. var theFunc = isc._makeFunction(variables, expression); return theFunc; }, //> @method isc.Func._getNextNonWhitespaceChar() (A) // // subroutine used by expressionToFunction(). gets the next non-whitespace character // after the given index. // // @params expression (string) String expression to evaluate return // @params index (number) index after which to look for nextChar //< _getNextNonWhitespaceChar : function (expression, index) { // set up a new nextChar var nextChar = isc._emptyString; for (var j = (index + 1); j < expression.length; j++) { if (!isc.isA.WhitespaceChar(expression.charAt(j))) { nextChar = expression.charAt(j); break; } } // we searched to the end of the string. if (j >= expression.length) nextChar = isc._emptyString; return nextChar; }, //> @method isc.Func.convertToMethod() // // A static version of class.convertToMethod() // This takes the an object and the name of a property as parameters, and (if legal) // attempts to convert the property to a function. // If the property's value is a function already, or the property is registered via // Class.registerStringMethods() as being a legitimate target to convert to a function, // return true. // Otherwise return false // // @param object (object) object with property to convert // @param functionName (string) name of the property to convert to a string. // // @return (boolean) false if this is not a function and cannot be converted // to one // //< convertToMethod : function (object, methodName) { // Handle bad parameters // XXX How to log this better - we know nothing about object, so can't do getID() or // whatever if (!isc.isAn.Object(object) || !isc.isA.nonemptyString(methodName)) { isc.Log.logWarn("convertToMethod() called with bad parameters. Cannot convert " + " property '" + methodName + "' on object " + object + " to a function. Returning false."); return false; } // If the value of this property is already a function - we don't need to make any // changes, and can assume it's a legal property value. if (object[methodName] && isc.isA.Function(object[methodName])) return true; // By default the _stringMethodregistry map object is a static property on the Class // of the object passed in. // If the object passed in is not a member of a subclass of 'Class', this is not the case. // In these cases assume the _stringMethodRegistry map has been assigned to the object // directly (for now) // XXX - Currently this is not really used anywhere in the code, but potentially could // be for stringMethods on (for example) the ListViewer data array. var registry = (isc.isAn.Instance(object) ? object.getClass()._stringMethodRegistry : object._stringMethodRegistry); // return false if there's no registry. if (registry == null) return false; var undefined; var methodParamsString = registry[methodName]; // If the value is not in the map, return false - this property can't legally be // converted to a function by us, so don't attempt it! // triple "=" - check for identity not equivalence, as having the argument string be // null is legitimate. // If this method is not listed in the stringMethodRegistry, we can't convert the // property value to a method. if (methodParamsString === undefined) return false; // We're dealing with a valid string method - attempt to convert the property value. isc.Func.replaceWithMethod(object, methodName, methodParamsString); // and return true to indicate that this is a legal slot for a function and should now // contain a function (if the conversion was possible). return true; }, //> @method isc.Func.replaceWithMethod() (A) // // Given an object with a string property, convert the string to a function // and assign it to the same property name. // // This is useful when you expect developers to pass a method (such as an event handler, // etc) as a string, but you need to execute it as a function. // // @params object (object) Object containing the property // @params methodName (string) Names of the method to convert from string to a function // @params variables (string) Names of variables to pass into the new function //< replaceWithMethod : function (object, methodName, variables, comment) { // If no string has been provided for the stringMethod, create a function with the // correct signature. Signature has to match so that you can observe an undefined // string method. if (object[methodName] == null) { object[methodName] = isc.is.emptyString(variables) ? isc.Class.NO_OP : new Function(variables, isc._emptyString); } var stringMethod = object[methodName]; // already converted if (isc.isA.Function(stringMethod)) return; var convertedMethod; if (isc.isA.String(stringMethod) || isc.isA.Object(stringMethod)) { // expressionToFunction can handle stringMethods and 'action' type objects convertedMethod = isc.Func.expressionToFunction(variables, stringMethod, comment); } else { isc.Log.logWarn("Property '" + methodName + "' on object " + object + " is of type " + typeof stringMethod + ". This can not be converted to a method.", "Function"); return; } // add the converted function to the object: var temp = {}; temp[methodName] = convertedMethod; isc.addMethods(object, temp); }});
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -