/// <summary> /// Executes the script. /// </summary> /// <param name="engine"> The script engine to use to execute the script. </param> /// <param name="parentScope"> The scope of the calling code. </param> /// <param name="thisObject"> The value of the "this" keyword in the calling code. </param> /// <returns> The result of evaluating the script. </returns> public object Execute(ScriptEngine engine, RuntimeScope parentScope, object thisObject) { if (engine == null) { throw new ArgumentNullException("engine"); } // Compile the code if it hasn't already been compiled. if (this.GeneratedMethod == null) { GenerateCode(); } // Package up all the runtime state. var context = ExecutionContext.CreateGlobalOrEvalContext(engine, parentScope, thisObject); // Execute the compiled delegate and store the result. object result = ((GlobalCodeDelegate)this.GeneratedMethod.GeneratedDelegate)(context); if (result == null) { result = Undefined.Value; } // Ensure the abstract syntax tree is kept alive until the eval code finishes running. GC.KeepAlive(this); // Return the result. return(result); }
/// <summary> /// Creates an execution context for code running as a result of a function call. /// </summary> /// <param name="engine"> A script engine. </param> /// <param name="parentScope"> The scope that was active when the function was declared /// (NOT when it was called). </param> /// <param name="thisValue"> The value of the 'this' keyword. </param> /// <param name="executingFunction"> The function that is being called. </param> /// <returns> A new execution context instance. </returns> internal static ExecutionContext CreateFunctionContext(ScriptEngine engine, RuntimeScope parentScope, object thisValue, UserDefinedFunction executingFunction) { if (thisValue == null) { throw new ArgumentNullException(nameof(thisValue)); } if (executingFunction == null) { throw new ArgumentNullException(nameof(executingFunction)); } return(new ExecutionContext(engine, parentScope, BindingStatus.Initialized, thisValue, executingFunction, null, executingFunction.Container)); }
private ExecutionContext(ScriptEngine engine, RuntimeScope parentScope, BindingStatus thisBindingStatus, object thisValue, UserDefinedFunction executingFunction, FunctionInstance newTarget, ObjectInstance functionContainer) { this.Engine = engine ?? throw new ArgumentNullException(nameof(engine)); this.ParentScope = parentScope; this.ThisBindingStatus = thisBindingStatus; this.thisValue = thisValue; this.ExecutingFunction = executingFunction; this.NewTarget = newTarget; this.FunctionContainer = functionContainer; }
// CODE-GEN METHODS //_________________________________________________________________________________________ /// <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="parentScope"> The scope at the point the function is declared. </param> /// <param name="bodyText"> The source code for the function body. </param> /// <param name="generatedMethod"> A delegate which represents the body of the function plus any dependencies. </param> /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param> /// <param name="container"> A reference to the containing class prototype or object literal (or <c>null</c>). </param> /// <remarks> This is used by functions declared in JavaScript code (including getters and setters). </remarks> public static UserDefinedFunction CreateFunction(ObjectInstance prototype, string name, IList <string> argumentNames, RuntimeScope parentScope, string bodyText, GeneratedMethod generatedMethod, bool strictMode, ObjectInstance container) { return(new UserDefinedFunction(prototype, name, argumentNames, parentScope, bodyText, generatedMethod, strictMode, container)); }
/// <summary> /// Creates an execution context for code running as a result of the new operator. The /// 'this' value is unavailable. /// </summary> /// <param name="engine"> A script engine. </param> /// <param name="parentScope"> The scope that was active when the class was declared. </param> /// <param name="executingFunction"> A reference to the function that is being executed. </param> /// <param name="newTarget"> The target of the new operator. </param> /// <param name="functionContainer"> A reference to the object literal or class prototype /// the executing function was defined within. Used by the 'super' keyword. </param> /// <returns> A new execution context instance. </returns> internal static ExecutionContext CreateDerivedContext(ScriptEngine engine, RuntimeScope parentScope, UserDefinedFunction executingFunction, FunctionInstance newTarget, ObjectInstance functionContainer) { return(new ExecutionContext(engine, parentScope, BindingStatus.Uninitialized, null, executingFunction, newTarget, functionContainer)); }
/// <summary> /// Creates an execution context for code running as a result of the new operator. /// </summary> /// <param name="engine"> A script engine. </param> /// <param name="parentScope"> The scope that was active when the class was declared. </param> /// <param name="thisValue"> The value of the 'this' keyword. </param> /// <param name="executingFunction"> A reference to the function that is being executed. </param> /// <param name="newTarget"> The target of the new operator. </param> /// <param name="functionContainer"> A reference to the object literal or class prototype /// the executing function was defined within. Used by the 'super' keyword. </param> /// <returns> A new execution context instance. </returns> internal static ExecutionContext CreateConstructContext(ScriptEngine engine, RuntimeScope parentScope, object thisValue, UserDefinedFunction executingFunction, FunctionInstance newTarget, ObjectInstance functionContainer) { return(new ExecutionContext(engine, parentScope, BindingStatus.Initialized, thisValue, executingFunction, newTarget, functionContainer)); }
/// <summary> /// Creates a new RuntimeScope instance, which is used for passing captured variables /// between methods. /// </summary> /// <param name="parent"> The parent scope, or <c>null</c> to use the ParentScope from this /// execution context. </param> /// <param name="scopeType"></param> /// <param name="varNames"></param> /// <param name="letNames"></param> /// <param name="constNames"></param> /// <returns> A new RuntimeScope instance. </returns> public RuntimeScope CreateRuntimeScope(RuntimeScope parent, ScopeType scopeType, string[] varNames, string[] letNames, string[] constNames) { return(new RuntimeScope(Engine, parent ?? ParentScope, scopeType, varNames, letNames, constNames)); }
/// <summary> /// Creates a new instance of the 'arguments' object. /// </summary> /// <param name="functionScope"> The top-level scope for the function. </param> /// <param name="arguments"> The argument values that were passed to the function. </param> /// <returns> A new instance of the 'arguments' object. </returns> public ArgumentsInstance CreateArgumentsInstance(RuntimeScope functionScope, object[] arguments) { return(new ArgumentsInstance(Engine.Object.InstancePrototype, ExecutingFunction, functionScope, arguments)); }
/// <summary> /// Creates an execution context for code running in an eval() scope. /// </summary> /// <param name="engine"> A script engine. </param> /// <param name="parentScope"> The scope that was active when eval() was called. </param> /// <param name="thisValue"> The value of the 'this' keyword. </param> /// <returns> A new execution context instance. </returns> internal static ExecutionContext CreateGlobalOrEvalContext(ScriptEngine engine, RuntimeScope parentScope, object thisValue) { if (thisValue == null) { throw new ArgumentNullException(nameof(thisValue)); } return(new ExecutionContext(engine, parentScope, BindingStatus.Initialized, thisValue, null, null, null)); }
/// <summary> /// Creates a new RuntimeScope instance. /// </summary> /// <param name="engine"> The script engine this scope is associated with. </param> /// <param name="parent"> The parent scope, or <c>null</c> if this is the root scope. </param> /// <param name="scopeType"></param> /// <param name="varNames"></param> /// <param name="letNames"></param> /// <param name="constNames"></param> internal RuntimeScope(ScriptEngine engine, RuntimeScope parent, ScopeType scopeType, string[] varNames, string[] letNames, string[] constNames) { this.Engine = engine ?? throw new ArgumentNullException(nameof(engine)); this.Parent = parent; this.ScopeType = scopeType; if (varNames != null && scopeType != ScopeType.TopLevelFunction && scopeType != ScopeType.EvalStrict) { var scope = this; while (scope != null && scope.ScopeObject == null && scope.ScopeType != ScopeType.TopLevelFunction && scopeType != ScopeType.EvalStrict) { scope = scope.Parent; } if (scope != null) { if (scope.ScopeType == ScopeType.TopLevelFunction || scopeType == ScopeType.EvalStrict) { foreach (var name in varNames) { if (!scope.values.ContainsKey(name)) { scope.values[name] = new LocalValue { Value = Undefined.Value, Flags = LocalFlags.Deletable } } } ; } else { var attributes = scopeType == ScopeType.Eval ? PropertyAttributes.FullAccess : PropertyAttributes.Enumerable | PropertyAttributes.Writable; foreach (var name in varNames) { scope.ScopeObject.InitializeMissingProperty(name, attributes); } } } varNames = null; } if (varNames != null || letNames != null || constNames != null) { values = new Dictionary <string, LocalValue>( (varNames != null ? varNames.Length : 0) + (letNames != null ? letNames.Length : 0) + (constNames != null ? constNames.Length : 0)); } if (varNames != null) { foreach (string variableName in varNames) { values[variableName] = new LocalValue { Value = Undefined.Value } } ; } if (letNames != null) { foreach (string variableName in letNames) { values[variableName] = new LocalValue(); } } if (constNames != null) { foreach (string variableName in constNames) { values[variableName] = new LocalValue { Flags = LocalFlags.ReadOnly } } ; } }