internal object CallHelper(ICallerContext context, object[] args, string[] names, object instance) { // we allow kw-arg binding to ctor's of arbitrary CLS types, but // NOT Python built-in types. After the ctor succeeds we'll set the kw args as // arbitrary properties on the CLS type. If this ends up being a built-in type we'll // do the check when we're going to set the kw-args. This accomplishes 2 things: // 1. Our error messages match CPython more closely // 2. The attribute lookup is done lazily only if kw-args are supplied to a ctor CoerceArgs(context, ref args, ref instance); KwArgBinder kwArgBinder = new KwArgBinder(context, args, names, targets[0].IsConstructor); MethodBinding bestBinding = new MethodBinding(); List<UnboundArgument> bestUnboundArgs = null; for (int i = 0; i < targets.Length; i++) { object[] realArgs = kwArgBinder.DoBind(targets[i], Name); if (realArgs != null) { MethodBinding mb = new MethodBinding(); mb.method = targets[i]; if (!CompilerHelpers.IsStatic(targets[i])) { if (instance == null) { if (realArgs.Length == 0) { throw Ops.TypeError("bad number of arguments for function {0}", targets[0].Name); } mb.instance = realArgs[0]; mb.arguments = new object[realArgs.Length - 1]; Array.Copy(realArgs, mb.arguments, realArgs.Length - 1); } else { mb.instance = instance; mb.arguments = realArgs; } } else { mb.arguments = realArgs; } if (!kwArgBinder.AllowUnboundArgs) { // we can have no better bindings! bestBinding = mb; break; } if (bestBinding.method == null || (kwArgBinder.UnboundArgs == null || (bestUnboundArgs != null && bestUnboundArgs.Count > kwArgBinder.UnboundArgs.Count))) { bestBinding = mb; bestUnboundArgs = kwArgBinder.UnboundArgs; } } } if (bestBinding.method != null) { // we've bound the arguments to a real method, // finally we're going to dispatch back to the // optimized version of the calls. object[] callArgs = bestBinding.arguments; ParameterInfo[] pis = bestBinding.method.GetParameters(); object[] dynamicArgs = new object[pis.Length]; for (int i = 0; i < pis.Length; i++) { dynamicArgs[i] = Ops.GetDynamicTypeFromType(pis[i].ParameterType); } FastCallable fc = (FastCallable)Overloads.GetKeywordArgumentOverload(new Tuple(true, dynamicArgs)); object ret; if (instance == null) ret = fc.Call(context, callArgs); else ret = fc.CallInstance(context, instance, callArgs); // any unbound arguments left over we assume the user // wants to do a property set with. We'll go ahead and try // that - if they fail we'll throw. if (bestUnboundArgs != null) { // if we had a constructor w/ a ref param then we'll try // updating the Tuple here instead of the user's object. if (targets[0].DeclaringType.IsDefined(typeof(PythonTypeAttribute), false)) { // calling ctor w/ kw-args w/ zero args, let it go, don't do any sets. if (args.Length == names.Length) return ret; throw Ops.TypeError("'{0}' is an invalid keyword argument for this function", bestUnboundArgs[0].Name, Name); } for (int j = 0; j < bestUnboundArgs.Count; j++) { Ops.SetAttr(DefaultContext.Default, ret, SymbolTable.StringToId(bestUnboundArgs[j].Name), bestUnboundArgs[j].Value); } } return ret; } if (kwArgBinder.GetError() != null) { throw kwArgBinder.GetError(); } throw Ops.TypeError("bad number of arguments for function {0}", FriendlyName); }
public override object Call(ICallerContext context, object[] args, string[] names) { KwArgBinder argBinder = new KwArgBinder(context, args, names); object[] defaults = this.Defaults; if (defaults.Length != ArgNames.Length) { // we need a 1<->1 mapping here for kwarg binder. object[] newDefs = new object[ArgNames.Length]; for (int i = 0; i < (nparams - defaults.Length); i++) { newDefs[i] = DBNull.Value; } Array.Copy(defaults, 0, newDefs, (nparams - defaults.Length), defaults.Length); defaults = newDefs; } object[] realArgs = argBinder.DoBind(Name, ArgNames, defaults, kwDictPos, argListPos); if (realArgs != null) { if (!EnforceRecursion) return target(realArgs); PushFrame(); try { return target(realArgs); } finally { PopFrame(); } } else if (argBinder.GetError() != null) { throw argBinder.GetError(); } else { throw BadArgumentError(args.Length); } }