/// <summary> /// Builds the return value of a call /// </summary> /// <param name="outParams">The out parameters indices, or null. See <see cref="BuildArgumentList" />.</param> /// <param name="pars">The parameters passed to the function.</param> /// <param name="retv">The return value from the function. Use DynValue.Void if the function returned no value.</param> /// <returns>A DynValue to be returned to scripts</returns> protected static R_VAL BuildReturnValue(RubyState state, List <int> outParams, object[] pars, object retv) { if (outParams == null) { return(RubyState.ObjectToValue(state, retv)); } else { R_VAL[] rets = new R_VAL[outParams.Count + 1]; if (retv is R_VAL && R_VAL.IsNil(( R_VAL )retv)) { rets[0] = R_VAL.NIL; } else { rets[0] = RubyState.ObjectToValue(state, retv); } for (int i = 0; i < outParams.Count; i++) { rets[i + 1] = RubyState.ObjectToValue(state, pars[outParams[i]]); } R_VAL ary = RubyDLL.r_ary_new(); foreach (var p in rets) { RubyDLL.r_ary_push(state, ary, p); } return(ary); } }
/// <summary> /// Builds the argument list. /// </summary> /// <param name="state">The ruby state.</param> /// <param name="obj">The object.</param> /// <param name="args">The arguments.</param> /// <param name="outParams">Output: A list containing the indices of all "out" parameters, or null if no out parameters are specified.</param> /// <returns>The arguments, appropriately converted.</returns> protected virtual object[] BuildArgumentList(RubyState state, object obj, CallbackArguments args, out List <int> outParams) { ParameterDescriptor[] parameters = Parameters; object[] pars = new object[parameters.Length]; int j = args.IsMethodCall ? 1 : 0; outParams = null; for (int i = 0; i < pars.Length; i++) { // keep track of out and ref params if (parameters[i].Type.IsByRef) { if (outParams == null) { outParams = new List <int> (); } outParams.Add(i); } // if an ext method, we have an obj -> fill the first param if (ExtensionMethodType != null && obj != null && i == 0) { pars[i] = obj; continue; } else if (parameters[i].Type == typeof(CallbackArguments)) { pars[i] = args.SkipMethodCall(); } // else, ignore out params else if (parameters[i].IsOut) { pars[i] = null; } else if (i == parameters.Length - 1 && VarArgsArrayType != null) { List <R_VAL> extraArgs = new List <R_VAL> (); while (true) { var arg = args.RawGet(j, false); j += 1; if (!R_VAL.IsNil(arg)) { extraArgs.Add(arg); } else { break; } } // here we have to worry we already have an array.. damn. We only support this for userdata. // remains to be analyzed what's the correct behavior here. For example, let's take a params object[].. // given a single table parameter, should it use it as an array or as an object itself ? if (extraArgs.Count == 1) { R_VAL arg = extraArgs[0]; if (R_VAL.IsData(arg)) { // if ( Framework.Do.IsAssignableFrom ( VarArgsArrayType, arg.UserData.Object.GetType () ) ) { // pars[ i ] = RubyDLL.ValueToDataObject< object > ( state, arg, RubyState.DATA_TYPE_PTR ); pars[i] = RubyState.ValueToRefObject(state, arg, DataTypePtr); continue; // } } } // ok let's create an array, and loop Array vararg = Array.CreateInstance(VarArgsElementType, extraArgs.Count); for (int ii = 0; ii < extraArgs.Count; ii++) { vararg.SetValue(RubyState.ValueToObjectOfType(state, extraArgs[ii], DataTypePtr, VarArgsElementType, null, false), ii); } pars[i] = vararg; } // else, convert it else { var arg = args.RawGet(j, false); pars[i] = RubyState.ValueToObjectOfType(state, arg, DataTypePtr, parameters[i].Type, parameters[i].DefaultValue, parameters[i].HasDefaultValue); j += 1; } } return(pars); }