Exemple #1
0
        /// <summary>
        /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.1
        /// </summary>
        public override JsValue Call(JsValue thisArg, JsValue[] arguments)
        {
            var strict = Strict || _engine._isStrict;

            using (new StrictModeScope(strict, true))
            {
                var localEnv = LexicalEnvironment.NewFunctionEnvironment(_engine, this, Undefined);
                _engine.EnterExecutionContext(localEnv, localEnv);

                try
                {
                    _engine.FunctionDeclarationInstantiation(
                        functionInstance: this,
                        arguments,
                        localEnv);

                    var result = _function.Execute();

                    var value = result.GetValueOrDefault().Clone();

                    if (result.Type == CompletionType.Throw)
                    {
                        ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
                    }

                    if (result.Type == CompletionType.Return)
                    {
                        return(value);
                    }
                }
                finally
                {
                    _engine.LeaveExecutionContext();
                }

                return(Undefined);
            }
        }
        /// <summary>
        /// https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist
        /// </summary>
        public override JsValue Call(JsValue thisArgument, JsValue[] arguments)
        {
            // ** PrepareForOrdinaryCall **
            // var callerContext = _engine.ExecutionContext;
            // Let calleeRealm be F.[[Realm]].
            // Set the Realm of calleeContext to calleeRealm.
            // Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]].
            var localEnv = LexicalEnvironment.NewFunctionEnvironment(_engine, this, Undefined);

            // If callerContext is not already suspended, suspend callerContext.
            // Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
            // NOTE: Any exception objects produced after this point are associated with calleeRealm.
            // Return calleeContext.

            _engine.EnterExecutionContext(localEnv, localEnv);

            // ** OrdinaryCallBindThis **

            JsValue thisValue;

            if (_thisMode == FunctionThisMode.Strict)
            {
                thisValue = thisArgument;
            }
            else
            {
                if (thisArgument.IsNullOrUndefined())
                {
                    var globalEnv    = _engine.GlobalEnvironment;
                    var globalEnvRec = (GlobalEnvironmentRecord)globalEnv._record;
                    thisValue = globalEnvRec.GlobalThisValue;
                }
                else
                {
                    thisValue = TypeConverter.ToObject(_engine, thisArgument);
                }
            }

            var envRec = (FunctionEnvironmentRecord)localEnv._record;

            envRec.BindThisValue(thisValue);

            // actual call

            var strict = _thisMode == FunctionThisMode.Strict || _engine._isStrict;

            using (new StrictModeScope(strict, true))
            {
                try
                {
                    var argumentsInstance = _engine.FunctionDeclarationInstantiation(
                        functionInstance: this,
                        arguments,
                        localEnv);

                    var result = _function.Execute();
                    var value  = result.GetValueOrDefault().Clone();
                    argumentsInstance?.FunctionWasCalled();

                    if (result.Type == CompletionType.Throw)
                    {
                        ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
                    }

                    if (result.Type == CompletionType.Return)
                    {
                        return(value);
                    }
                }
                finally
                {
                    _engine.LeaveExecutionContext();
                }

                return(Undefined);
            }
        }