// INITIALIZATION //_________________________________________________________________________________________ /// <summary> /// Creates a new instance of a user-defined function. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="name"> The name of the function. </param> /// <param name="argumentsText"> A comma-separated list of arguments. </param> /// <param name="bodyText"> The source code for the body of the function. </param> /// <remarks> This is used by <c>new Function()</c>. </remarks> internal UserDefinedFunction(ObjectInstance prototype, string name, string argumentsText, string bodyText) : base(prototype) { if (name == null) { throw new ArgumentNullException("name"); } if (argumentsText == null) { throw new ArgumentNullException("argumentsText"); } if (bodyText == null) { throw new ArgumentNullException("bodyText"); } // Set up a new function scope. var scope = DeclarativeScope.CreateFunctionScope(this.Engine.CreateGlobalScope(), name, null); // Compile the code. var context = new FunctionMethodGenerator(this.Engine, scope, name, argumentsText, bodyText, new CompilerOptions()); context.GenerateCode(); this.ArgumentsText = argumentsText; this.ArgumentNames = context.Arguments.Select(a => a.Name).ToList(); this.BodyText = bodyText; this.generatedMethod = context.GeneratedMethod; this.body = (FunctionDelegate)this.generatedMethod.GeneratedDelegate; this.ParentScope = this.Engine.CreateGlobalScope(); this.StrictMode = context.StrictMode; InitProperties(name, context.Arguments.Count); }
/// <summary> /// Creates a new instance of a user-defined function. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="name"> The name of the function. </param> /// <param name="args"> The names of the arguments. MUST include 'this'.</param> /// <param name="bodyText"> The source code for the body of the function. </param> internal static UserDefinedFunction Create(ScriptEngine engine, string name, List <ArgVariable> args, string bodyText) { if (args == null) { args = new List <ArgVariable>(); args.Add(new ArgVariable("this")); } if (name == null) { throw new ArgumentNullException("name"); } if (args == null) { throw new ArgumentNullException("args"); } if (bodyText == null) { throw new ArgumentNullException("bodyText"); } // Set up a new function scope. var scope = DeclarativeScope.CreateFunctionScope(engine.GlobalScope, name, args); // Compile the code. var context = new FunctionMethodGenerator(engine, scope, name, args, bodyText, new CompilerOptions()); context.GenerateCode(new OptimizationInfo(engine)); return(context.GeneratedMethods[0]); }
// INITIALIZATION //_________________________________________________________________________________________ /// <summary> /// Creates a new instance of a user-defined function. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="name"> The name of the function. </param> /// <param name="argumentNames"> The names of the arguments. </param> /// <param name="bodyText"> The source code for the body of the function. </param> internal UserDefinedFunction(ObjectInstance prototype, string name, IList <string> argumentNames, string bodyText) : base(prototype) { if (name == null) { throw new ArgumentNullException("name"); } if (argumentNames == null) { throw new ArgumentNullException("argumentNames"); } if (bodyText == null) { throw new ArgumentNullException("bodyText"); } // Set up a new function scope. var scope = DeclarativeScope.CreateFunctionScope(this.Engine.CreateGlobalScope(), name, argumentNames); // Compile the code. var context = new FunctionMethodGenerator(this.Engine, scope, name, argumentNames, bodyText, new CompilerOptions()); context.GenerateCode(); // Create a new user defined function. Init(name, argumentNames, this.Engine.CreateGlobalScope(), bodyText, context.GeneratedMethod, context.StrictMode, true); }
public object InstallBundle(Jurassic.ScriptEngine engine) { var baristaInstance = engine.GetGlobalValue("barista") as BaristaGlobal; if (baristaInstance == null) { throw new InvalidOperationException("Barista Global bundle could not be obtained."); } var dependencyResultObj = engine.Object.Construct(); //Require all dependencies.. foreach (var dependency in m_dependencies) { var result = baristaInstance.Common.Require(dependency.Key, null); dependencyResultObj.SetPropertyValue(dependency.Value, result, false); } //If it's a function dependency, execute that. if (this.ScriptFunction != null) { var args = new List <object>(); if (this.ScriptFunction is UserDefinedFunction) { var udf = this.ScriptFunction as UserDefinedFunction; args.AddRange(udf.ArgumentNames.Select(argumentName => dependencyResultObj.HasProperty(argumentName) ? dependencyResultObj.GetPropertyValue(argumentName) : Null.Value)); } return(this.ScriptFunction.Call(engine.Global, args.ToArray())); } //Use the implemented "include" function to include the scripts. //this promotes loose coupling between the script bundle and the include. var variableNames = dependencyResultObj.Properties.Select(pn => pn.Name).ToArray(); var resultArray = engine.Array.Construct(); foreach (var scriptReference in m_scriptReferences) { //Create a new scope, and eval the script within the new scope. var scope = DeclarativeScope.CreateRuntimeScope(engine.CreateGlobalScope(), variableNames); foreach (var property in dependencyResultObj.Properties) { if (property.Value == Undefined.Value || property.Value == Null.Value || property.Value == null) { continue; } scope.SetValue(property.Name, property.Value); } var result = baristaInstance.Include(scriptReference, scope, engine.Global, engine.ForceStrictMode); ArrayInstance.Push(resultArray, result); } return(resultArray.Length == 1 ? resultArray[0] : resultArray); }
/// <summary> /// Compiles the function (if it hasn't already been compiled) and returns a delegate /// representing the compiled function. /// </summary> private FunctionDelegate Compile() { if (this.m_body == null) { // Compile the function. var scope = DeclarativeScope.CreateFunctionScope(this.Engine.CreateGlobalScope(), this.Name, this.ArgumentNames); var functionGenerator = new FunctionMethodGenerator(this.Engine, scope, this.Name, this.ArgumentNames, this.BodyText, new CompilerOptions()); functionGenerator.GenerateCode(); this.m_generatedMethod = functionGenerator.GeneratedMethod; this.m_body = (FunctionDelegate)this.m_generatedMethod.GeneratedDelegate; } return(this.m_body); }
// INITIALIZATION //_________________________________________________________________________________________ /// <summary> /// Creates a new instance of a user-defined function. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="name"> The name of the function. </param> /// <param name="argumentsText"> A comma-separated list of arguments. </param> /// <param name="bodyText"> The source code for the body of the function. </param> /// <remarks> This is used by <c>new Function()</c>. </remarks> internal UserDefinedFunction(ObjectInstance prototype, string name, string argumentsText, string bodyText) : base(prototype) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (argumentsText == null) { throw new ArgumentNullException(nameof(argumentsText)); } if (bodyText == null) { throw new ArgumentNullException(nameof(bodyText)); } // Set up a new function scope. this.Scope = DeclarativeScope.CreateFunctionScope(ObjectScope.CreateGlobalScope(this.Engine.Global), name, null); // Compile the code. var context = new FunctionMethodGenerator(this.Scope, name, argumentsText, bodyText, new CompilerOptions() { #if ENABLE_DEBUGGING EnableDebugging = this.Engine.EnableDebugging, #endif ForceStrictMode = this.Engine.ForceStrictMode, EnableILAnalysis = this.Engine.EnableILAnalysis, CompatibilityMode = this.Engine.CompatibilityMode }); try { context.GenerateCode(); } catch (SyntaxErrorException ex) { throw new JavaScriptException(this.Engine, ErrorType.SyntaxError, ex.Message, ex.LineNumber, ex.SourcePath); } this.ArgumentsText = argumentsText; this.ArgumentNames = context.Arguments.Select(a => a.Name).ToList(); this.BodyText = bodyText; this.generatedMethod = context.GeneratedMethod; this.body = (FunctionDelegate)this.generatedMethod.GeneratedDelegate; this.ParentScope = ObjectScope.CreateGlobalScope(this.Engine.Global); this.StrictMode = context.StrictMode; InitProperties(name, context.Arguments.Count); }
// INITIALIZATION //_________________________________________________________________________________________ /// <summary> /// Creates a new Arguments instance. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="callee"> The function that was called. </param> /// <param name="scope"> The function scope. </param> /// <param name="argumentValues"> The argument values that were passed to the function. </param> public ArgumentsInstance(ObjectInstance prototype, UserDefinedFunction callee, DeclarativeScope scope, object[] argumentValues) : base(prototype) { if (callee == null) { throw new ArgumentNullException("callee"); } if (scope == null) { throw new ArgumentNullException("scope"); } if (argumentValues == null) { throw new ArgumentNullException("argumentValues"); } this.m_callee = callee; this.m_scope = scope; this.FastSetProperty("length", argumentValues.Length, PropertyAttributes.NonEnumerable, false); if (this.m_callee.StrictMode == false) { this.FastSetProperty("callee", callee, PropertyAttributes.NonEnumerable, false); // Create an array mappedArguments where mappedArguments[i] = true means a mapping is // maintained between arguments[i] and the corresponding variable. this.m_mappedArguments = new bool[argumentValues.Length]; var mappedNames = new Dictionary <string, int>(); // maps argument name -> index for (int i = 0; i < argumentValues.Length; i++) { if (i < callee.ArgumentNames.Count) { // Check if the argument name appeared previously in the argument list. int previousIndex; if (mappedNames.TryGetValue(callee.ArgumentNames[i], out previousIndex)) { // The argument name has appeared before. Remove the getter/setter. this.DefineProperty(previousIndex.ToString(), new PropertyDescriptor(argumentValues[previousIndex], PropertyAttributes.FullAccess), false); // The argument is no longer mapped. this.m_mappedArguments[previousIndex] = false; } // Add the argument name and index to the hashtable. mappedNames[callee.ArgumentNames[i]] = i; // The argument is mapped by default. this.m_mappedArguments[i] = true; // Define a getter and setter so that the property value reflects that of the argument. var getter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentGetter", new string[0], this.m_scope, "return " + callee.ArgumentNames[i], ArgumentGetter, true); getter.SetPropertyValue("argumentIndex", i, false); var setter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentSetter", new[] { "value" }, this.m_scope, callee.ArgumentNames[i] + " = value", ArgumentSetter, true); setter.SetPropertyValue("argumentIndex", i, false); this.DefineProperty(i.ToString(), new PropertyDescriptor(getter, setter, PropertyAttributes.FullAccess), false); } else { // This argument is unnamed - no mapping needs to happen. this[(uint)i] = argumentValues[i]; } } } else { // In strict mode, arguments items are not connected to the variables. for (int i = 0; i < argumentValues.Length; i++) { this[(uint)i] = argumentValues[i]; } // In strict mode, accessing caller or callee is illegal. var throwErrorFunction = new ThrowTypeErrorFunction(this.Engine.Function.InstancePrototype); this.DefineProperty("caller", new PropertyDescriptor(throwErrorFunction, throwErrorFunction, PropertyAttributes.Sealed), false); this.DefineProperty("callee", new PropertyDescriptor(throwErrorFunction, throwErrorFunction, PropertyAttributes.Sealed), false); } }