コード例 #1
0
        /// <summary>
        /// Calls the specified function, supporting most cases. The called function must not yield.
        /// </summary>
        /// <param name="func">The function; it must be a Function or ClrFunction or have a call metamethod defined.</param>
        /// <param name="args">The arguments.</param>
        /// <returns></returns>
        /// <exception cref="ScriptRuntimeException">If the function yields, returns a tail call request with continuations/handlers or, of course, if it encounters errors.</exception>
        public DynValue Call(DynValue func, params DynValue[] args)
        {
            if (func.Type == DataType.Function)
            {
                return(this.GetScript().Call(func, args));
            }
            else if (func.Type == DataType.ClrFunction)
            {
                while (true)
                {
                    DynValue ret = func.Callback.Invoke(this, args, false);

                    if (ret.Type == DataType.YieldRequest)
                    {
                        throw ScriptRuntimeException.CannotYield();
                    }
                    else if (ret.Type == DataType.TailCallRequest)
                    {
                        var tail = ret.TailCallData;

                        if (tail.Continuation != null || tail.ErrorHandler != null)
                        {
                            throw new ScriptRuntimeException("the function passed cannot be called directly. wrap in a script function instead.");
                        }
                        else
                        {
                            args = tail.Args;
                            func = tail.Function;
                        }
                    }
                    else
                    {
                        return(ret);
                    }
                }
            }
            else
            {
                int maxloops = 10;

                while (maxloops > 0)
                {
                    DynValue v = this.GetMetamethod(func, "__call");

                    if (v == null && v.IsNil())
                    {
                        throw ScriptRuntimeException.AttemptToCallNonFunc(func.Type);
                    }

                    func = v;

                    if (func.Type == DataType.Function || func.Type == DataType.ClrFunction)
                    {
                        return(Call(func, args));
                    }
                }

                throw ScriptRuntimeException.LoopInCall();
            }
        }
コード例 #2
0
        private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null, CallbackFunction continuation = null, bool thisCall = false, string debugText = null, DynValue unwindHandler = null)
        {
            DynValue fn = m_ValueStack.Peek(argsCount);

            if (fn.Type == DataType.ClrFunction)
            {
                IList <DynValue> args = new Slice <DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);

                // we expand tuples before callbacks
                // args = DynValue.ExpandArgumentsToList(args);
                SourceRef sref = GetCurrentSourceRef(instructionPtr);

                m_ExecutionStack.Push(new CallStackItem()
                {
                    ClrFunction              = fn.Callback,
                    ReturnAddress            = instructionPtr,
                    CallingSourceRef         = sref,
                    BasePointer              = -1,
                    ErrorHandler             = handler,
                    Continuation             = continuation,
                    ErrorHandlerBeforeUnwind = unwindHandler,
                });

                var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback, sref), args, isMethodCall: thisCall);
                m_ValueStack.RemoveLast(argsCount + 1);
                m_ValueStack.Push(ret);

                m_ExecutionStack.Pop();

                return(Internal_CheckForTailRequests(null, instructionPtr));
            }
            else if (fn.Type == DataType.Function)
            {
                m_ValueStack.Push(DynValue.NewNumber(argsCount));
                m_ExecutionStack.Push(new CallStackItem()
                {
                    BasePointer              = m_ValueStack.Count,
                    ReturnAddress            = instructionPtr,
                    Debug_EntryPoint         = fn.Function.EntryPointByteCodeLocation,
                    CallingSourceRef         = GetCurrentSourceRef(instructionPtr),
                    ClosureScope             = fn.Function.ClosureContext,
                    ErrorHandler             = handler,
                    Continuation             = continuation,
                    ErrorHandlerBeforeUnwind = unwindHandler,
                });
                return(fn.Function.EntryPointByteCodeLocation);
            }
            else
            {
                var metatable = GetMetatable(fn);

                if (metatable != null)
                {
                    var m = metatable.RawGet("__call");

                    if (m != null && m.IsNotNil())
                    {
                        DynValue[] tmp = new DynValue[argsCount + 1];
                        for (int i = 0; i < argsCount + 1; i++)
                        {
                            tmp[i] = m_ValueStack.Pop();
                        }

                        m_ValueStack.Push(m);

                        for (int i = argsCount; i >= 0; i--)
                        {
                            m_ValueStack.Push(tmp[i]);
                        }

                        return(Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation));
                    }
                }

                throw ScriptRuntimeException.AttemptToCallNonFunc(fn.Type, debugText);
            }
        }