/// <summary> /// Resolves a function instance via the .NET stack. /// </summary> private static UserDefinedFunction ResolveFunctionInstance(int count) { // First, get the stack: System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(5 + count, true); for (int i = 0; i < trace.FrameCount; i++) { System.Diagnostics.StackFrame frame = trace.GetFrame(i); UserDefinedFunction func = MethodLookup.Search(frame.GetMethod() as MethodInfo); if (func != null) { return(func); } } return(null); }
/// <summary> /// Creates a new function instance. /// </summary> /// <param name="argumentsAndBody"> The argument names plus the function body. </param> /// <returns> A new function instance. </returns> public static FunctionInstance OnConstruct(ScriptEngine engine, params string[] argumentsAndBody) { // Passing no arguments results in an empty function. if (argumentsAndBody.Length == 0) { return(UserDefinedFunction.Create(engine, "anonymous", null, string.Empty)); } // Split any comma-delimited names. List <ArgVariable> args = new List <ArgVariable>(); args.Add(new ArgVariable("this")); for (int i = 0; i < argumentsAndBody.Length - 1; i++) { var splitNames = argumentsAndBody[i].Split(','); for (int j = 0; j < splitNames.Length; j++) { // Trim any whitespace from the start and end of the argument name. string argumentName = Nitrassic.Library.String.Trim(splitNames[j]); if (argumentName == string.Empty) { throw new JavaScriptException(engine, "SyntaxError", "Unexpected ',' in argument"); } // Check the name is valid and resolve any escape sequences. argumentName = Compiler.Lexer.ResolveIdentifier(engine, argumentName); if (argumentName == null) { throw new JavaScriptException(engine, "SyntaxError", "Expected identifier"); } args.Add(new ArgVariable(argumentName)); } } // Create a new function. return(UserDefinedFunction.Create(engine, "anonymous", args, argumentsAndBody[argumentsAndBody.Length - 1])); }
// OVERRIDES //_________________________________________________________________________________________ /// <summary> /// Calls this function, passing in the given "this" value and zero or more arguments. /// </summary> /// <param name="thisObj"> The value of the "this" keyword within the function. </param> /// <param name="argumentValues"> An array of argument values to pass to the function. </param> /// <returns> The value that was returned from the function. </returns> public override object CallLateBound(ScriptEngine engine, params object[] thisAndArgumentValues) { // Call the function, passing the hoisted values too. int hoisted = HoistValues.Length; int argCount = thisAndArgumentValues.Length; object[] set = new object[hoisted + argCount]; // Transfer 'this': set[0] = thisAndArgumentValues; // Copy hoist values in: System.Array.Copy(HoistValues, 0, set, 1, hoisted); // Copy arg values in: System.Array.Copy(thisAndArgumentValues, 1, set, hoisted + 1, argCount - 1); // Need to find the correct compiled version of the host: UserDefinedFunction udf = Host.GetCompiled(engine, set); return(udf.body.Invoke(null, set)); }