/// <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(); } }
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); } }