/// <summary>
/// Prepares arguments for argfull overload.
/// </summary>
/// <param name="routine">Routine for which arguments should be prepared</param>
/// <param name="arguments">Arguments to be prepared for the routine</param>
/// <param name="genericArguments">Amount of generic arguments provided by call site.</param>
/// <param name="regularArguments">Amount of value arguments provided by call site.</param>
/// <param name="restrictions">Type restrictions for the arguments</param>
/// <returns>Array of prepared arguments to be called with routine</returns>
/// <remarks>
/// This is basically substitute for everything important that was done in argless overload (except it doesn't use PhpStack but evaluation stack).
/// It adopts the arguments according to routine. e.g. dereference reference if value is needed, supplies default argument, etc.
/// </remarks>
public static Expression[] PrepareArguments(this PhpRoutine routine, DynamicMetaObject[] arguments, int genericArguments, int regularArguments, out BindingRestrictions restrictions)
{
const int scriptContextIndex = 0;
DynamicMetaObject arg;
int result_offset = 0;
int argument_offset = 0;
Expression[] result = new Expression[1 + routine.Signature.GenericParamCount + routine.Signature.ParamCount];//ScriptContext + all arguments = actual arguments to be passed to argfull overload
restrictions = BindingRestrictions.Empty;
result[scriptContextIndex] = arguments[scriptContextIndex].Expression;
++result_offset;
++argument_offset;
// peek pseudo-generic arguments:
for (int i = 0; i < routine.Signature.GenericParamCount; ++i)
{
if (i < genericArguments)
{
arg = arguments[argument_offset + i];
}
else
{
arg = null;
}
result[result_offset + i] = GeneratePeekPseudoGenericArgument(routine, arguments[scriptContextIndex], arg, i);
// it isn't necessary to add restriction for type argument, it is always DTypeDesc
}
result_offset += routine.Signature.GenericParamCount;
argument_offset += genericArguments;
// peek regular arguments:
// skip first one ScriptContext and generic parameters
for (int i = 0; i < routine.Signature.ParamCount; ++i)
{
if (i < regularArguments)
{
arg = arguments[argument_offset + i];
if (arg.RuntimeType != null)
restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(arguments[argument_offset + i].Expression, arguments[argument_offset + i].LimitType));
else
restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(arguments[argument_offset + i].Expression, null));//(MB) is it necessary?
}
else
{
arg = null;
}
result[result_offset + i] = GeneratePeekArgument(routine, arguments[scriptContextIndex], arg, i);
}
return result;
}