Example #1
0
        public JsValue EvaluateCallExpression(CallExpression callExpression)
        {
            var callee = EvaluateExpression(callExpression.Callee);

            if (_engine.Options._IsDebugMode)
            {
                _engine.DebugHandler.AddToDebugCallStack(callExpression);
            }

            JsValue thisObject;

            // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4


            JsValue[] arguments;

            if (callExpression.Cached)
            {
                arguments = callExpression.CachedArguments;
            }
            else
            {
                arguments = callExpression.Arguments.Select(EvaluateExpression).Select(_engine.GetValue).ToArray();

                if (callExpression.CanBeCached)
                {
                    // The arguments array can be cached if they are all literals
                    if (callExpression.Arguments.All(x => x is Literal))
                    {
                        callExpression.CachedArguments = arguments;
                        callExpression.Cached          = true;
                    }
                    else
                    {
                        callExpression.CanBeCached = false;
                    }
                }
            }

            var func = _engine.GetValue(callee);

            var r = callee as Reference;

            if (_engine.Options._MaxRecursionDepth >= 0)
            {
                var stackItem = new CallStackElement(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");

                var recursionDepth = _engine.CallStack.Push(stackItem);

                if (recursionDepth > _engine.Options._MaxRecursionDepth)
                {
                    _engine.CallStack.Pop();
                    throw new RecursionDepthOverflowException(_engine.CallStack, stackItem.ToString());
                }
            }

            if (func == Undefined.Instance)
            {
                throw new JavaScriptException(_engine.TypeError, r == null ? "" : string.Format("Object has no method '{0}'", (callee as Reference).GetReferencedName()));
            }

            if (!func.IsObject())
            {
                throw new JavaScriptException(_engine.TypeError, r == null ? "" : string.Format("Property '{0}' of object is not a function", (callee as Reference).GetReferencedName()));
            }

            var callable = func.TryCast <ICallable>();

            if (callable == null)
            {
                throw new JavaScriptException(_engine.TypeError);
            }

            if (r != null)
            {
                if (r.IsPropertyReference())
                {
                    thisObject = r.GetBase();
                }
                else
                {
                    var env = r.GetBase().TryCast <EnvironmentRecord>();
                    thisObject = env.ImplicitThisValue();
                }
            }
            else
            {
                thisObject = Undefined.Instance;
            }

            // is it a direct call to eval ? http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.1.1
            if (r != null && r.GetReferencedName() == "eval" && callable is EvalFunctionInstance)
            {
                return(((EvalFunctionInstance)callable).Call(thisObject, arguments, true));
            }

            var result = callable.Call(thisObject, arguments);

            if (_engine.Options._IsDebugMode)
            {
                _engine.DebugHandler.PopDebugCallStack();
            }

            if (_engine.Options._MaxRecursionDepth >= 0)
            {
                _engine.CallStack.Pop();
            }

            return(result);
        }
Example #2
0
        public JsValue EvaluateCallExpression(CallExpression callExpression)
        {
            var callee = EvaluateExpression(callExpression.Callee);

            if (_engine.Options.IsDebugMode())
            {
                _engine.DebugHandler.AddToDebugCallStack(callExpression);
            }

            JsValue thisObject;

            // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
            var arguments = callExpression.Arguments.Select(EvaluateExpression).Select(_engine.GetValue).ToArray();

            var func = _engine.GetValue(callee);
            
            var r = callee as Reference;

            var isRecursionHandled = _engine.Options.GetMaxRecursionDepth() >= 0;
            if (isRecursionHandled)
            {
                var stackItem = new CallStackElement(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");

                var recursionDepth = _engine.CallStack.Push(stackItem);

                if (recursionDepth > _engine.Options.GetMaxRecursionDepth())
                {
                    _engine.CallStack.Pop();
                    throw new RecursionDepthOverflowException(_engine.CallStack, stackItem.ToString());
                }
            }

            if (func == Undefined.Instance)
            {
                throw new JavaScriptException(_engine.TypeError, r == null ? "" : string.Format("Object has no method '{0}'", (callee as Reference).GetReferencedName()));
            }

            if (!func.IsObject())
            {
                throw new JavaScriptException(_engine.TypeError, r == null ? "" : string.Format("Property '{0}' of object is not a function", (callee as Reference).GetReferencedName()));
            }

            var callable = func.TryCast<ICallable>();
            if (callable == null)
            {
                throw new JavaScriptException(_engine.TypeError);
            }
            
            if (r != null)
            {
                if (r.IsPropertyReference())
                {
                    thisObject = r.GetBase();
                }
                else
                {
                    var env = r.GetBase().TryCast<EnvironmentRecord>();
                    thisObject = env.ImplicitThisValue();
                }
            }
            else
            {
                thisObject = Undefined.Instance;
            }

            // is it a direct call to eval ? http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.1.1
            if (r != null && r.GetReferencedName() == "eval" && callable is EvalFunctionInstance)
            {
                return ((EvalFunctionInstance) callable).Call(thisObject, arguments, true);
            }
            
            var result = callable.Call(thisObject, arguments);

            if (_engine.Options.IsDebugMode())
            {
                _engine.DebugHandler.PopDebugCallStack();
            }

            if (isRecursionHandled)
            {
                _engine.CallStack.Pop();
            }

            return result;
        }