/// <summary> /// Creates a new FunctionContext instance. /// </summary> /// <param name="engine"> The script engine. </param> /// <param name="scope"> The function scope. </param> /// <param name="functionName"> The name of the function. </param> /// <param name="argumentNames"> The names of the arguments. </param> /// <param name="body"> The source code for the body of the function. </param> /// <param name="options"> Options that influence the compiler. </param> public FunctionMethodGenerator(ScriptEngine engine, DeclarativeScope scope, string functionName, IList <string> argumentNames, string body, CompilerOptions options) : base(engine, scope, new StringScriptSource(body), options) { this.Name = functionName; this.ArgumentNames = argumentNames; this.BodyText = body; }
/// <summary> /// Creates a new FunctionContext instance. /// </summary> /// <param name="engine"> The script engine. </param> /// <param name="scope"> The function scope. </param> /// <param name="functionName"> The name of the function. </param> /// <param name="argumentNames"> The names of the arguments. </param> /// <param name="body"> The source code for the body of the function. </param> /// <param name="options"> Options that influence the compiler. </param> public FunctionMethodGenerator(ScriptEngine engine, DeclarativeScope scope, string functionName, IList<string> argumentNames, string body, CompilerOptions options) : base(engine, scope, new StringScriptSource(body), options) { this.Name = functionName; this.ArgumentNames = argumentNames; this.BodyText = body; }
/// <summary> /// Creates a new declarative scope for use inside a function body (and within function /// argument default values). /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="functionName"> The name of the function. Can be empty for an anonymous function. </param> /// <param name="argumentNames"> The names of each of the function arguments. Can be <c>null</c>. </param> /// <returns> A new DeclarativeScope instance. </returns> internal static DeclarativeScope CreateFunctionScope(Scope parentScope, string functionName, IEnumerable <string> argumentNames) { if (parentScope == null) { throw new ArgumentNullException("parentScope", "Function scopes must have a parent scope."); } if (functionName == null) { throw new ArgumentNullException(nameof(functionName)); } var result = new DeclarativeScope(parentScope, 0); if (string.IsNullOrEmpty(functionName) == false) { result.DeclareVariable(functionName); } result.DeclareVariable("this"); result.DeclareVariable("arguments"); if (argumentNames != null) { foreach (var argumentName in argumentNames) { result.DeclareVariable(argumentName); } } return(result); }
/// <summary> /// Creates a new FunctionContext instance. /// </summary> /// <param name="scope"> The function scope. </param> /// <param name="functionName"> The name of the function. </param> /// <param name="argumentsText"> A comma-separated list of arguments. </param> /// <param name="body"> The source code for the body of the function. </param> /// <param name="options"> Options that influence the compiler. </param> public FunctionMethodGenerator(DeclarativeScope scope, string functionName, string argumentsText, string body, CompilerOptions options) : base(scope, new StringScriptSource(body), options) { this.Name = functionName; this.ArgumentsText = argumentsText; this.BodyText = body; }
/// <summary> /// Creates a new FunctionMethodGenerator instance. /// </summary> /// <param name="engine"> The script engine. </param> /// <param name="scope"> The function scope. </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 of the function. </param> /// <param name="body"> The root of the abstract syntax tree for the body of the function. </param> /// <param name="scriptPath"> The URL or file system path that the script was sourced from. </param> /// <param name="options"> Options that influence the compiler. </param> public FunctionMethodGenerator(ScriptEngine engine, DeclarativeScope scope, string functionName, IList<string> argumentNames, string bodyText, Statement body, string scriptPath, CompilerOptions options) : base(engine, scope, new DummyScriptSource(scriptPath), options) { this.Name = functionName; this.ArgumentNames = argumentNames; this.BodyRoot = body; this.BodyText = bodyText; Validate(); }
/// <summary> /// Creates a new FunctionMethodGenerator instance. /// </summary> /// <param name="engine"> The script engine. </param> /// <param name="scope"> The function scope. </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 of the function. </param> /// <param name="body"> The root of the abstract syntax tree for the body of the function. </param> /// <param name="scriptPath"> The URL or file system path that the script was sourced from. </param> /// <param name="options"> Options that influence the compiler. </param> public FunctionMethodGenerator(ScriptEngine engine, DeclarativeScope scope, string functionName, IList <string> argumentNames, string bodyText, Statement body, string scriptPath, CompilerOptions options) : base(engine, scope, new DummyScriptSource(scriptPath), options) { this.Name = functionName; this.ArgumentNames = argumentNames; this.BodyRoot = body; this.BodyText = bodyText; Validate(); }
/// <summary> /// Creates a new declarative scope for use inside a catch statement. /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="catchVariableName"> The name of the catch variable. </param> /// <returns> A new DeclarativeScope instance. </returns> internal static DeclarativeScope CreateCatchScope(Scope parentScope, string catchVariableName) { if (parentScope == null) throw new ArgumentNullException("parentScope", "Catch scopes must have a parent scope."); if (catchVariableName == null) throw new ArgumentNullException("catchVariableName"); var result = new DeclarativeScope(parentScope, 0); result.DeclareVariable(catchVariableName); result.CanDeclareVariables = false; // Only the catch variable can be declared in this scope. return result; }
/// <summary> /// Creates a new declarative scope for use at runtime. /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="declaredVariableNames"> The names of variables that were declared in this scope. </param> /// <returns> A new DeclarativeScope instance. </returns> public static DeclarativeScope CreateRuntimeScope(Scope parentScope, string[] declaredVariableNames) { if (parentScope == null) throw new ArgumentNullException("parentScope", "Function scopes must have a parent scope."); if (declaredVariableNames == null) throw new ArgumentNullException("declaredVariableNames"); var result = new DeclarativeScope(parentScope, declaredVariableNames.Length); foreach (string variableName in declaredVariableNames) result.DeclareVariable(variableName); result.values = new object[result.DeclaredVariableCount]; return result; }
/// <summary> /// Creates a new FunctionMethodGenerator instance. /// </summary> /// <param name="scope"> The function scope. </param> /// <param name="functionName"> The name of the function. </param> /// <param name="declarationType"> Indicates how the function was declared. </param> /// <param name="arguments"> The names and default values of the arguments. </param> /// <param name="bodyText"> The source code of the function. </param> /// <param name="body"> The root of the abstract syntax tree for the body of the function. </param> /// <param name="scriptPath"> The URL or file system path that the script was sourced from. </param> /// <param name="span"> The extent of the function in the source code. </param> /// <param name="options"> Options that influence the compiler. </param> public FunctionMethodGenerator(DeclarativeScope scope, string functionName, FunctionDeclarationType declarationType, IList <FunctionArgument> arguments, string bodyText, Statement body, string scriptPath, SourceCodeSpan span, CompilerOptions options) : base(scope, new DummyScriptSource(scriptPath), options) { this.Name = functionName; this.DeclarationType = declarationType; this.Arguments = arguments; this.BodyRoot = body; this.BodyText = bodyText; Validate(span.StartLine, scriptPath); }
/// <summary> /// Creates a new declarative scope for use inside a catch statement. /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="catchVariableName"> The name of the catch variable. </param> /// <returns> A new DeclarativeScope instance. </returns> internal static DeclarativeScope CreateCatchScope(Scope parentScope, string catchVariableName) { if (parentScope == null) { throw new ArgumentNullException("parentScope", "Catch scopes must have a parent scope."); } if (catchVariableName == null) { throw new ArgumentNullException(nameof(catchVariableName)); } var result = new DeclarativeScope(parentScope, 0); result.DeclareVariable(catchVariableName); result.CanDeclareVariables = false; // Only the catch variable can be declared in this scope. return(result); }
/// <summary> /// Creates a new declarative scope for use inside a function body. /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="functionName"> The name of the function. Can be empty for an anonymous function. </param> /// <param name="argumentNames"> The names of each of the function arguments. </param> /// <returns> A new DeclarativeScope instance. </returns> internal static DeclarativeScope CreateFunctionScope(Scope parentScope, string functionName, IEnumerable<string> argumentNames) { if (parentScope == null) throw new ArgumentNullException("parentScope", "Function scopes must have a parent scope."); if (functionName == null) throw new ArgumentNullException("functionName"); if (argumentNames == null) throw new ArgumentNullException("argumentNames"); var result = new DeclarativeScope(parentScope, 0); if (string.IsNullOrEmpty(functionName) == false) result.DeclareVariable(functionName); result.DeclareVariable("this"); result.DeclareVariable("arguments"); foreach (var argumentName in argumentNames) result.DeclareVariable(argumentName); return result; }
/// <summary> /// Creates a new declarative scope for use at runtime. /// </summary> /// <param name="parentScope"> A reference to the parent scope. Can not be <c>null</c>. </param> /// <param name="declaredVariableNames"> The names of variables that were declared in this scope. </param> /// <returns> A new DeclarativeScope instance. </returns> public static DeclarativeScope CreateRuntimeScope(Scope parentScope, string[] declaredVariableNames) { if (parentScope == null) { throw new ArgumentNullException("parentScope", "Function scopes must have a parent scope."); } if (declaredVariableNames == null) { throw new ArgumentNullException(nameof(declaredVariableNames)); } var result = new DeclarativeScope(parentScope, declaredVariableNames.Length); foreach (string variableName in declaredVariableNames) { result.DeclareVariable(variableName); } result.values = new object[result.DeclaredVariableCount]; return(result); }
/// <summary> /// Parses the source text into an abstract syntax tree. /// </summary> public override void Parse() { var lexer = new Lexer(this.Engine, this.Source); var parser = new Parser(this.Engine, lexer, this.InitialScope, this.Options, CodeContext.Eval); // If the eval() is running strict mode, create a new scope. parser.DirectivePrologueProcessedCallback = parser2 => { if (parser2.StrictMode == true) { parser2.InitialScope = parser2.Scope = DeclarativeScope.CreateEvalScope(parser2.Scope); } }; this.AbstractSyntaxTree = parser.Parse(); this.StrictMode = parser.StrictMode; this.InitialScope = parser.Scope; this.MethodOptimizationHints = parser.MethodOptimizationHints; }
// 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.callee = callee; this.scope = scope; this.FastSetProperty("length", argumentValues.Length, PropertyAttributes.NonEnumerable); if (this.callee.StrictMode == false) { this.FastSetProperty("callee", callee, PropertyAttributes.NonEnumerable); // Create an array mappedArguments where mappedArguments[i] = true means a mapping is // maintained between arguments[i] and the corresponding variable. this.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) == true) { // 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.mappedArguments[previousIndex] = false; } // Add the argument name and index to the hashtable. mappedNames[callee.ArgumentNames[i]] = i; // The argument is mapped by default. this.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.scope, "return " + callee.ArgumentNames[i], ArgumentGetter, true); getter.SetPropertyValue("argumentIndex", i, false); var setter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentSetter", new string[] { "value" }, this.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); } }