using System.Linq; using Jint.Native.Object; using Jint.Parser; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Environments; namespace Jint.Native.Function { /// /// /// public sealed class ScriptFunctionInstance : FunctionInstance, IConstructor { private readonly IFunctionDeclaration _functionDeclaration; /// /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2 /// /// /// /// /// public ScriptFunctionInstance(Engine engine, IFunctionDeclaration functionDeclaration, LexicalEnvironment scope, bool strict) : base(engine, functionDeclaration.Parameters.Select(x => x.Name).ToArray(), scope, strict) { _functionDeclaration = functionDeclaration; Engine = engine; Extensible = true; Prototype = engine.Function.PrototypeObject; DefineOwnProperty("length", new PropertyDescriptor(new JsValue(FormalParameters.Length), false, false, false ), false); var proto = engine.Object.Construct(Arguments.Empty); proto.DefineOwnProperty("constructor", new PropertyDescriptor(this, true, false, true), false); DefineOwnProperty("prototype", new PropertyDescriptor(proto, true, false, false ), false); if (_functionDeclaration.Id != null) { DefineOwnProperty("name", new PropertyDescriptor(_functionDeclaration.Id.Name, null, null, null), false); } if (strict) { var thrower = engine.Function.ThrowTypeError; DefineOwnProperty("caller", new PropertyDescriptor(thrower, thrower, false, false), false); DefineOwnProperty("arguments", new PropertyDescriptor(thrower, thrower, false, false), false); } } /// /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.1 /// /// /// /// public override JsValue Call(JsValue thisArg, JsValue[] arguments) { using (new StrictModeScope(Strict, true)) { // setup new execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3 JsValue thisBinding; if (StrictModeScope.IsStrictModeCode) { thisBinding = thisArg; } else if (thisArg == Undefined.Instance || thisArg == Null.Instance) { thisBinding = Engine.Global; } else if (!thisArg.IsObject()) { thisBinding = TypeConverter.ToObject(Engine, thisArg); } else { thisBinding = thisArg; } var localEnv = LexicalEnvironment.NewDeclarativeEnvironment(Engine, Scope); Engine.EnterExecutionContext(localEnv, localEnv, thisBinding); try { Engine.DeclarationBindingInstantiation( DeclarationBindingType.FunctionCode, _functionDeclaration.FunctionDeclarations, _functionDeclaration.VariableDeclarations, this, arguments); var result = Engine.ExecuteStatement(_functionDeclaration.Body); if (result.Type == Completion.Throw) { JavaScriptException ex = new JavaScriptException(result.GetValueOrDefault()) .SetCallstack(Engine, result.Location); throw ex; } if (result.Type == Completion.Return) { return result.GetValueOrDefault(); } } finally { Engine.LeaveExecutionContext(); } return Undefined.Instance; } } /// /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.2 /// /// /// public ObjectInstance Construct(JsValue[] arguments) { var proto = Get("prototype").TryCast(); var obj = new ObjectInstance(Engine); obj.Extensible = true; obj.Prototype = proto ?? Engine.Object.PrototypeObject; var result = Call(obj, arguments).TryCast(); if (result != null) { return result; } return obj; } public ObjectInstance PrototypeObject { get; private set; } } }